依赖属性的困难

发布于 2024-12-28 15:56:24 字数 3944 浏览 4 评论 0原文

我的 Windows Phone Mango 应用程序上的依赖属性遇到了一些问题。以下是我想要动态更改其字体大小的两个控件:

<TextBlock Text="{Binding}" FontSize="{Binding ElementName=ParagraphItems, Path=DataContext.TextScale}" />
<local:HyperlinkTextBlock Text="{Binding}" FontSize="{Binding ElementName=ParagraphItems, Path=DataContext.TextScale}"  />

TextBlock 工作正常,但 HyperlinkTextBlock 不行。 HyperlinkTextBlock 是我制作的一个类:

<UserControl
  <!-- ... -->
  >

    <RichTextBox x:Name="LayoutRoot" TextWrapping="Wrap" FontSize="{Binding FontSize}">
        <Paragraph x:Name="BaseParagraph" />
    </RichTextBox> 

</UserControl>

public partial class HyperlinkTextBlock : UserControl { /* ... */ }

我不确定需要在 HyperlinkTextBlock 中做什么才能使其能够接收 FontSize在 XAML 中声明时的值。我尝试绑定到 HyperlinkTextBlock.xaml 中的属性,并在代码隐藏中更改属性时发出通知:(

    public new double FontSize
    {
        get
        {
            return base.FontSize;
        }
        set
        {
            base.FontSize = value;
            onPropChanged("FontSize");
        }
    }

它是 new 因为 UserControl 已经有a FontSize 属性 - 我不应该使用它吗?)

我还尝试创建一个全新的依赖属性:

    public static readonly new DependencyProperty FontSizeProperty = DependencyProperty.RegisterAttached(
        "FontSize",
        typeof(double),
        typeof(HyperlinkTextBlock),
        new PropertyMetadata(20, new PropertyChangedCallback(onFontSizeChanged)));

    public new double FontSize
    {
        get { return (double)GetValue(FontSizeProperty); }
        set { SetValue(FontSizeProperty, value); }
    }

    private static void onFontSizeChanged(DependencyObject dependObj, DependencyPropertyChangedEventArgs e)
    {
        ((HyperlinkTextBlock)dependObj).LayoutRoot.FontSize = (double)e.NewValue;
    }

同样,这不起作用。在运行时,它会给出错误:

System.ArgumentException was unhandled
  Message=Default value type does not match type of property.
  StackTrace:
       at System.Windows.DependencyProperty.Register(Boolean fIsAttachedDP, String name, Type propertyType, Type ownerType, PropertyMetadata propertyMetadata, Boolean readOnly)
       at System.Windows.DependencyProperty.RegisterAttached(String name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
       at MyApp.Views.HyperlinkTextBlock..cctor()
       at System.Reflection.RuntimeConstructorInfo.InternalInvoke(RuntimeConstructorInfo rtci, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)
       at System.Reflection.RuntimeConstructorInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
       at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)
       at MS.Internal.TypeProxy.<>c__DisplayClass30.<GetCreateObjectDelegate>b__2a()
       at MS.Internal.TypeProxy.CreateInstance(UInt32 customTypeId)
       at MS.Internal.XamlManagedRuntimeRPInvokes.CreateInstance(XamlTypeToken inXamlType, XamlQualifiedObject& newObject)

执行此操作的正确方法是什么?

更新

如果我直接在HyperlinkTextBlock上设置FontSize

     <local:HyperlinkTextBlock Text="{Binding}" Margin="0,15" FontSize="33.0" />
     <local:HyperlinkTextBlock Text="{Binding}" Margin="0,15" FontSize="40" />

并从HyperlinkTextBlock<中删除有关FontSize的任何内容/code> 本身:

<RichTextBox x:Name="LayoutRoot" TextWrapping="Wrap">
    <Paragraph x:Name="BaseParagraph" />
</RichTextBox>

那么设置字体大小没有明显的效果。 (上面声明的两个文本块看起来相同。)

I'm having a bit of trouble with dependency properties on my Windows Phone Mango app. Here are two controls whose font size I'd like to change dynamically:

<TextBlock Text="{Binding}" FontSize="{Binding ElementName=ParagraphItems, Path=DataContext.TextScale}" />
<local:HyperlinkTextBlock Text="{Binding}" FontSize="{Binding ElementName=ParagraphItems, Path=DataContext.TextScale}"  />

The TextBlock works fine, but the HyperlinkTextBlock does not. HyperlinkTextBlock is a class I've made:

<UserControl
  <!-- ... -->
  >

    <RichTextBox x:Name="LayoutRoot" TextWrapping="Wrap" FontSize="{Binding FontSize}">
        <Paragraph x:Name="BaseParagraph" />
    </RichTextBox> 

</UserControl>

public partial class HyperlinkTextBlock : UserControl { /* ... */ }

I'm not sure what I need to do in HyperlinkTextBlock to make it so it can receive FontSize values when it is declared in XAML. I tried binding to the property in HyperlinkTextBlock.xaml, and notifying when the property changes in code-behind:

    public new double FontSize
    {
        get
        {
            return base.FontSize;
        }
        set
        {
            base.FontSize = value;
            onPropChanged("FontSize");
        }
    }

(It's new because UserControl already has a FontSize property - shouldn't I just be able to use that?)

I also tried creating an entirely new dependency property:

    public static readonly new DependencyProperty FontSizeProperty = DependencyProperty.RegisterAttached(
        "FontSize",
        typeof(double),
        typeof(HyperlinkTextBlock),
        new PropertyMetadata(20, new PropertyChangedCallback(onFontSizeChanged)));

    public new double FontSize
    {
        get { return (double)GetValue(FontSizeProperty); }
        set { SetValue(FontSizeProperty, value); }
    }

    private static void onFontSizeChanged(DependencyObject dependObj, DependencyPropertyChangedEventArgs e)
    {
        ((HyperlinkTextBlock)dependObj).LayoutRoot.FontSize = (double)e.NewValue;
    }

Similarly, this did not work. At runtime, it gives the error:

System.ArgumentException was unhandled
  Message=Default value type does not match type of property.
  StackTrace:
       at System.Windows.DependencyProperty.Register(Boolean fIsAttachedDP, String name, Type propertyType, Type ownerType, PropertyMetadata propertyMetadata, Boolean readOnly)
       at System.Windows.DependencyProperty.RegisterAttached(String name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
       at MyApp.Views.HyperlinkTextBlock..cctor()
       at System.Reflection.RuntimeConstructorInfo.InternalInvoke(RuntimeConstructorInfo rtci, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)
       at System.Reflection.RuntimeConstructorInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
       at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)
       at MS.Internal.TypeProxy.<>c__DisplayClass30.<GetCreateObjectDelegate>b__2a()
       at MS.Internal.TypeProxy.CreateInstance(UInt32 customTypeId)
       at MS.Internal.XamlManagedRuntimeRPInvokes.CreateInstance(XamlTypeToken inXamlType, XamlQualifiedObject& newObject)

What is the right way to go about doing this?

Update:

If I just set FontSize directly on HyperlinkTextBlock:

     <local:HyperlinkTextBlock Text="{Binding}" Margin="0,15" FontSize="33.0" />
     <local:HyperlinkTextBlock Text="{Binding}" Margin="0,15" FontSize="40" />

And remove anything about FontSize from HyperlinkTextBlock itself:

<RichTextBox x:Name="LayoutRoot" TextWrapping="Wrap">
    <Paragraph x:Name="BaseParagraph" />
</RichTextBox>

Then there is no observable effect of setting the font size. (The two text blocks declared above appear identical.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

留蓝 2025-01-04 15:56:24

像这样更改依赖属性代码:

public static readonly new DependencyProperty FontSizeProperty = DependencyProperty.RegisterAttached(
    "FontSize",
    typeof(double),
    typeof(HyperlinkTextBlock),
    new PropertyMetadata((double)20, new PropertyChangedCallback(onFontSizeChanged)));

Int is not a double...

Change the dependency property code like this:

public static readonly new DependencyProperty FontSizeProperty = DependencyProperty.RegisterAttached(
    "FontSize",
    typeof(double),
    typeof(HyperlinkTextBlock),
    new PropertyMetadata((double)20, new PropertyChangedCallback(onFontSizeChanged)));

An int is not a double...

清浅ˋ旧时光 2025-01-04 15:56:24

也许我没有得到什么,但为什么你将 FontSize 定义为附加属性?我会使用一个简单的依赖属性,为了避免任何混淆,我会给它一个与 FontSize 不同的名称(例如本例中的 HyperlinkFontSize),所以我会这样做:(

public static readonly DependencyProperty HyperlinkFontSize = DependencyProperty.Register(
    "HyperlinkFontSize",
    typeof(double),
    typeof( HyperlinkTextBlock ),
    new PropertyMetadata( 20.0, onFontSizeChanged) ) );

请注意,您不必提供当您传递事件处理程序时委托类型的名称。)

然后像这样进行绑定:

<local:HyperlinkTextBlock Text="{Binding}" HyperlinkFontSize="{Binding ElementName=ParagraphItems, Path=DataContext.TextScale}" />

最后一件事:首先您尝试将 FontSize 实现为普通属性(带有更改通知)。这永远不会起作用,因为数据绑定的目标始终必须是依赖属性(尽管源可以是任何 CLR 属性,即使没有更改通知),如所述 此处


更新:另一种方法是将 RichTextbox.FontSize 属性绑定到用户控件的 FontSize 属性,如下所示:

<UserControl x:Name="hyperlinkTextboxUserControl" ...>

    <RichTextBox x:Name="LayoutRoot" TextWrapping="Wrap" FontSize="{Binding FontSize, ElementName=hyperlinkTextboxUserControl}">
        <Paragraph x:Name="BaseParagraph" />
    </RichTextBox> 

</UserControl>

这样您就不需要额外的依赖属性,您可以简单地在 local:HyperlinkTextBlock 上设置 FontSize,例如你原来是这么做的。

Maybe I am not getting something, but why do you define FontSize as an attached property? I would go with a simple dependency property, and to avoid any confusion, I would give it a different name than FontSize (e. g. HyperlinkFontSize in this case), so I would do something like this:

public static readonly DependencyProperty HyperlinkFontSize = DependencyProperty.Register(
    "HyperlinkFontSize",
    typeof(double),
    typeof( HyperlinkTextBlock ),
    new PropertyMetadata( 20.0, onFontSizeChanged) ) );

(Note that you do not have to provide the name of the delegate type when you pass the event handler.)

And then do the binding like this:

<local:HyperlinkTextBlock Text="{Binding}" HyperlinkFontSize="{Binding ElementName=ParagraphItems, Path=DataContext.TextScale}" />

And one last thing: at first you tried to implement the FontSize as an ordinary property (with change notification). That never should work, because the target of data binding always has to be a dependency property (although the source can be any CLR property, even without change notification), as stated here.


UPDATE: Another approach would be to bind the RichTextbox.FontSize property to the FontSize property of the user control, something like this:

<UserControl x:Name="hyperlinkTextboxUserControl" ...>

    <RichTextBox x:Name="LayoutRoot" TextWrapping="Wrap" FontSize="{Binding FontSize, ElementName=hyperlinkTextboxUserControl}">
        <Paragraph x:Name="BaseParagraph" />
    </RichTextBox> 

</UserControl>

That way you do not need the extra dependency property, and you can simply set the FontSize on the local:HyperlinkTextBlock like you originally did.

千仐 2025-01-04 15:56:24

除非 Silverlight 5 和 Windows Phone 的 Silverlight 之间有什么不同,否则 FontSize 值应自动从其父级继承。您不需要创建任何依赖属性,也不需要在 UserControl 内进行任何绑定。我刚刚测试了以下内容(尽管在 PC 上)并且它有效:

<UserControl x:Class="Test.HyperlinkTextBlock"
      <!-- ... -->
    >    
        <RichTextBox x:Name="LayoutRoot" TextWrapping="Wrap">
            <Paragraph x:Name="BaseParagraph">HyperlinkTextBox text</Paragraph>
        </RichTextBox>  
</UserControl>

<UserControl.Resources>
    <system:Double x:Key="SomethingToBindTo">28.0</system:Double>
</UserControl.Resources>

<StackPanel Margin="20">
    <TextBlock  Text="TextBlock text" FontSize="{Binding Source={StaticResource SomethingToBindTo}}" />
    <my:HyperLinkTextBlock FontSize="{Binding Source={StaticResource SomethingToBindTo}}" />
</StackPanel>

就是结果:

result

更新:

确保删除/注释您添加的 FontSize 属性,否则我的示例将无法工作。

如果这仍然不适合您,并且由于 Silverlight 4 及更早版本没有 FindAncestor 标记扩展,也许命名您的 UserControl并使用它来绑定您的 RichTextBox。

<UserControl x:Class="Test.HyperlinkTextBox" Name="UserControlRoot"
      <!-- ... -->
    >   
        <RichTextBox x:Name="LayoutRoot"
                     TextWrapping="Wrap"
                     FontSize="{Binding ElementName=UserControlRoot, Path=FontSize}">
            <Paragraph x:Name="BaseParagraph">Text</Paragraph>
        </RichTextBox>
</UserControl>

Unless something's different between Silverlight 5 and Windows Phone's Silverlight, the FontSize value should automatically be inherited from its parent. You don't need to created any dependency properties, and you don't need to make any bindings inside your UserControl. I just tested the following (on PC though) and it worked:

<UserControl x:Class="Test.HyperlinkTextBlock"
      <!-- ... -->
    >    
        <RichTextBox x:Name="LayoutRoot" TextWrapping="Wrap">
            <Paragraph x:Name="BaseParagraph">HyperlinkTextBox text</Paragraph>
        </RichTextBox>  
</UserControl>

and

<UserControl.Resources>
    <system:Double x:Key="SomethingToBindTo">28.0</system:Double>
</UserControl.Resources>

<StackPanel Margin="20">
    <TextBlock  Text="TextBlock text" FontSize="{Binding Source={StaticResource SomethingToBindTo}}" />
    <my:HyperLinkTextBlock FontSize="{Binding Source={StaticResource SomethingToBindTo}}" />
</StackPanel>

This was the result:

result

Update:

Make sure to remove/comment the FontSize property you added, or my example won't work.

If that still doesn't work for you, and since Silverlight 4 and earlier doesn't have the FindAncestor mark-up extension, perhaps name your UserControl and use that to bind your RichTextBox to.

<UserControl x:Class="Test.HyperlinkTextBox" Name="UserControlRoot"
      <!-- ... -->
    >   
        <RichTextBox x:Name="LayoutRoot"
                     TextWrapping="Wrap"
                     FontSize="{Binding ElementName=UserControlRoot, Path=FontSize}">
            <Paragraph x:Name="BaseParagraph">Text</Paragraph>
        </RichTextBox>
</UserControl>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文