Сложность с DependencyProperties - PullRequest
1 голос
/ 23 января 2012

У меня небольшие проблемы со свойствами зависимостей в приложении 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 уже имеет свойство 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 ]

2 голосов
/ 23 января 2012

Измените код свойства зависимости следующим образом:

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

int не является двойным ...

1 голос
/ 23 января 2012

Может быть, я что-то не получаю, но почему вы определяете 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>

Таким образом, вам не нужно дополнительное свойство зависимости, ивы можете просто установить FontSize для локального: HyperlinkTextBlock, как вы это делали изначально.

0 голосов
/ 23 января 2012

Если между Silverlight 5 и Silverlight для Windows Phone что-то не так, значение FontSize должно автоматически наследоваться от его родителя.Вам не нужно создавать какие-либо свойства зависимостей, и вам не нужно делать никаких привязок внутри вашего UserControl.Я только что проверил следующее (хотя на ПК), и оно заработало:

<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>
...