Режим привязки DependencyProperty twoway, но свойствоchangedeventhandler равно нулю - PullRequest
1 голос
/ 22 апреля 2011

Я пытаюсь следовать парадигме проектирования MVVM с C # и XAML.У меня проблемы с вложенным пользовательским элементом управления.Я пытаюсь привязать элемент во вложенном пользовательском элементе управления к одному из значений в ViewModel (которое связано с View через свойство DataContext).Одна и та же ViewModel используется как для внешних, так и для вложенных пользовательских элементов управления.

Он частично работает как есть, но изменения идут только в одну сторону от ViewModel к вложенному пользовательскому элементу управления.Мне нужно, чтобы изменения, внесенные во вложенный пользовательский элемент управления, распространялись обратно на ViewModel.

Начиная с XAML для основного представления, у меня есть:

<UserControl>

   <!-- ... -->

   <UserControl.DataContext>
      <local:MyViewModel x:Name="myViewModel" />
   </UserControl.DataContext>

   <!-- ... -->

   <local:NestedUserControl
      x:Name="nestedUserControl"
      CustomNestedValue="{Binding Path=CustomValue, ElementName=myViewModel, Mode=TwoWay}" />

</UserControl>

В коде C # дляViewModel:

// Constructor
public MyViewModel()
{
   CustomValue = true;
}

private bool _customValue;
public bool CustomValue
{
   get { return _customValue; }
   set
   {
       if (_customValue != value)
       {
          _customValue = value;
          RaisePropertyChanged ("CustomValue");
       }
   }
}

И в коде NestedUserControl у меня есть:

public static readonly DependencyProperty CustomNestedValueProperty =
   DependencyProperty.Register (
      "CustomNestedValue",
      typeof (bool),
      typeof (NestedUserControl),
      new FrameworkPropertyMetatdata
      {
         BindsTwoWayByDefault = true,
         PropertyChangedCallback = 
            new PropertyChangedCallback (CustomNestedValueChangedCallback)
      });

public bool CustomNestedValue
{
   get { return (bool) GetValue (CustomNestedValueProperty); }
   set { SetValue (CustomNestedValueProperty, value); }
}

protected static void CustomNestedValueChangedCallback (
   DependencyObject Source,
   DependencyPropertyChangedEventArgs e)
{
   bool value = (bool) e.NewValue;
   NestedUserControl control = source as NestedUserControl;
   control.OnCustomValueChange (value);
}

public void OnCustomValueChange (bool value)
{
   RaisePropertyChanged ("CustomNestedValue");

   // Do other stuff ...
}

// This function is where the nested user control gets direct
// interactions from the user which cause the dependency
// property to change.  When this event occurs, the change needs
// to be communicated back up to the view model.
private void _onPreviewMouseDown (object sender, MouseButtonEventArgs e)
{
   CustomNestedValue = !CustomNestedValue;
}

[Примечание: я не только устанавливаю режим привязки на TwoWayпри установке привязки в XAML, но я попытался сделать это поведением по умолчанию для DependencyProperty в приведенном выше коде.Не повезло.]

И код для вложенного пользовательского элемента управления, и код ViewModel содержат приведенное ниже PropertyChangedEventHandler событие / ответ, которое необходимо для интерфейса INotifyPropertyChanged.Из того, что я понимаю, это то, как привязки между элементами XAML и ViewModel синхронизируются.

public event PropertyChangedEventHandler PropertyChanged;

protected void RaisePropertyChanged(string propertyName)
{
   try
   {
      if (this.PropertyChanged != null)
         this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   }
   catch (Exception e)
   {
      //  ...
   }
}

Когда я запускаю код, всякий раз, когда для NestedUserControl вызывается функция RaisePropertyChanged,PropertyChanged событие всегда null .Это проблема только для вложенного пользовательского контроля, а не внешнего.Разве это событие не должно устанавливаться автоматически через механизм привязки?

Я боролся с этим уже несколько дней, но безрезультатно.Любая помощь приветствуется.Спасибо!

1 Ответ

2 голосов
/ 22 апреля 2011

Привязка к DependencyObject работает без использования интерфейса INotifyPropertyChanged.Фактически, если вы установите точку останова в получателе или установщике свойства CustomNestedValue свойства NestedUserControl, вы обнаружите, что оно никогда не будет достигнуто при связывании в XAML.По сути, INotifyPropertyChanged - это способ достижения привязки без снижения от DependencyObject.

Когда MyViewModel.CustomValue привязан к NestedUserControl, код привязки вызывает (в псевдокоде):

NestedUserControl.SetBinding(binding, NestedUserControl.CustomNestedValueProperty)

Событие INotifyPropertyChanged.PropertyChanged никогда не регистрируется и останется нулевым.Тем не менее, это не обязательно отвечает, почему значение не возвращается в ViewModel.

В любом случае, вы можете удалить несколько движущихся частей и пойти с

public static readonly DependencyProperty CustomNestedValueProperty =
    DependencyProperty.Register("CustomNestedValue",
                                typeof (bool),
                                typeof (NestedUserControl),
                                null);

public bool CustomNestedValue
{
    get { return (bool) GetValue (CustomNestedValueProperty); }
    set { SetValue (CustomNestedValueProperty, value); }
}

.моих DependencyProperties написаны, и они поддерживают TwoWay привязку.

...