Привязка DependencyProperty не происходит при начальной загрузке

Я пытаюсь сделать что-то простое - создать DependencyProperty, а затем привязать к нему. Тем не менее, при запуске приложения средство получения не запускается. (Я предполагаю, что решение заставит меня шлепнуть головой и сказать: "Дох!", Но все же.:))

Есть идеи?

Код с выделенным кодом:

public static readonly DependencyProperty PriorityProperty = 
        DependencyProperty.Register("Priority", 
        typeof (Priority), typeof (PriorityControl), null);

public Priority Priority
{
    get { return (Priority)GetValue(PriorityProperty); }
    set { SetValue(PriorityProperty, value); }
}

Контроль XAML:

<ListBox Background="Transparent" 
         BorderThickness="0" 
         ItemsSource="{Binding Path=Priorities}" 
         Name="PriorityList" 
         SelectedItem="{Binding Path=Priority, Mode=TwoWay}">
  <ListBox.ItemTemplate>
    <DataTemplate>
        <Grid Height="16" Width="16">
          <Border BorderBrush="Black"
                  BorderThickness="2"
                  CornerRadius="3"
                  Visibility="{Binding RelativeSource=
                       {RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}, Path=IsSelected, Converter={StaticResource boolToVisibilityConverter}}" />
          <Border CornerRadius="3" Height="12" Width="12">
            <Border.Background>
              <SolidColorBrush Color="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}, Path=Content, Converter={StaticResource priorityToColorConverter}}" />
            </Border.Background>
          </Border>
        </Grid>
    </DataTemplate>
   </ListBox.ItemTemplate>
   <ListBox.ItemsPanel>
     <ItemsPanelTemplate>
       <StackPanel Orientation="Horizontal"/>
     </ItemsPanelTemplate>
   </ListBox.ItemsPanel>
 </ListBox>

Обязательное заявление:

<UI:PriorityControl Grid.Column="8" 
                    Priority="{Binding Path=Priority}" 
                    VerticalAlignment="Center"/>

Некоторые другие заметки:

  • Связывание в UserControl
  • UserControl содержит PriorityControl
  • PriorityControl содержит свойство DependencyProperty
  • Я проверил, что данные UserControl получают соответствующие данные - все остальные привязки работают.
  • Если я изменю выбор на PriorityControl с помощью мыши, все срабатывает соответствующим образом. Это просто первоначальная установка значения, которая не работает.
  • Приоритет - это перечисление.

РЕДАКТИРОВАТЬ: я пробовал две дополнительные вещи. Сначала я сделал привязку к значению двусторонним, но это не сработало. Затем я добавил свойство с измененным обратным вызовом в свойство зависимостей и заставил его вызывать OnPropertyChanged, например так:

public static readonly DependencyProperty PriorityProperty =
        DependencyProperty.Register("Priority", typeof (Priority), typeof (PriorityControl), new PropertyMetadata(HandleValueChanged));

private static void HandleValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
   var npc = dependencyObject as PriorityControl;
   npc.OnPropertyChanged("Priority");
}

Это тоже не сработало. I even tried overriding ApplyTemplate on the control to force a property change notification, but the value is never getting set on initial load. I can change values and see everything fire just fine, but it's that first time that nothing is coming through.

3 ответа

Решение

Метод получения и установки свойства DependencyProperty не вызывается никем, кроме вас!

Они просто помощники, созданные для вашей выгоды (чтобы сэкономить вам кучу кастингов и вызовов GetValue/SetValue).

Вся работа в DP (анимация, привязка и т. Д.) Происходит напрямую через вызовы SetValue и GetValue.

Если вам нужно поймать изменение в значении, предоставьте обратный вызов изменения в регистре вызовов.

Примечание: прикрепленные свойства (т.е. с использованием RegisterAttached вместо Register) на самом деле используют сеттер при разборе XAML, но это другая история, так как обычные DP этого не делают.

Обновить:

Вы не установили значение по умолчанию в своем реестре, поэтому по умолчанию оно равно 0 (что является вашим значением перечисления "Normal"). Если вы установите это в качестве первого значения в привязке, оно не изменится, поэтому оно не сработает.

Одно из решений: добавьте перечисление none в качестве первого значения 0, чтобы "Normal" (значение 1) вызывало изменение. В качестве альтернативы установите значение по умолчанию в регистре, которое не является "нормальным".

Я заметил, что при выполнении свойств зависимости, если значение уже было задано во время определения свойства, оно не будет работать правильно. Вы сказали, что при установке значения в приложении проблем не было, поэтому я предполагаю, что проблем с сантехникой нет.

Рассмотрим пример ниже:

XAML

<UI:PriorityControl Priority="{Binding Path=Priority, Mode=TwoWay}"/>

Код

public enum Priority
{
    Normal,
    Low,
    High
}

public class PriorityControl : UserControl
{    
    public static readonly DependencyProperty PriorityProperty =
      DependencyProperty.Register("Priority", typeof(Priority), typeof(PriorityControl), new PropertyMetadata(DependencyProperty.UnsetValue, OnPriorityPropertyChanged);

    public Priority Priority
    {
        get { return (Priority)this.GetValue(PriorityProperty); }
        set { this.SetValue(PriorityProperty, value); }
    }

    private static void OnPriorityPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        PriorityControl control = sender as PriorityControl;
        if (control != null)
        {
            // Do what you wanted to here.
        }
    }
}

Если вы используете перечисление и не указываете значение по умолчанию (которое, по-видимому, не указывается при отсутствии объекта PropertyMetadata для свойства зависимостей при создании), значением по умолчанию будет значение по умолчанию для перечисления. В моем примере выше это было бы "Нормально". Теперь, если вы попытаетесь установить значение Normal при создании элемента управления, обратный вызов не будет вызван, потому что значение уже равно этому значению.

Чтобы это работало правильно, вы должны передать DependencyProperty.UnsetValue объекту PropertyMetadata, как я это делал, когда определял свойство. Это позволит вызывать метод OnPriorityPropertyChanged при первоначальном задании значения.

Надеюсь, что это поможет исправить это!

Не уверен на 100%, но это может быть так же просто, как изменить приоритетную привязку на TwoWay.

<UI:PriorityControl Grid.Column="8" 
                    Priority="{Binding Path=Priority, Mode=TwoWay}" 
                    VerticalAlignment="Center"/>
Другие вопросы по тегам