DependencyProperties的难度

时间:2012-01-23 17:51:09

标签: c# silverlight dependency-properties windows-phone

我的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中我需要做什么才能使它在XAML中声明时可以接收FontSize值。我尝试绑定到HyperlinkTextBlock.xaml中的属性,并在代码隐藏时通知属性更改:

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

new因为UserControl已经拥有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)

这样做的正确方法是什么?

更新

如果我直接在FontSize上设置HyperlinkTextBlock

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

FontSize本身删除HyperlinkTextBlock的任何内容:

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

然后没有设置字体大小的可观察效果。 (上面声明的两个文本块看起来完全相同。)

3 个答案:

答案 0 :(得分:2)

更改依赖项属性代码,如下所示:

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

int不是双...

答案 1 :(得分:1)

也许我没有得到什么,但为什么要将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属性,即使没有更改通知),如here所述。


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

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

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

</UserControl>

这样你就不需要额外的依赖属性了,只需像你原来那样在本地:HyperlinkTextBlock上设置FontSize。

答案 2 :(得分:0)

除非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>