2016-10-11 2 views
2

У меня сейчас есть расширенный набор инструментов WPF Toolkit Color Picker. Когда я выбираю цвет в подборщике цветов, цвет границы изменяется на выбранный цвет. Это работает прямо сейчас, смотрите следующий GIF:INotifyPropertyChanged ничего не делает

enter image description here

Есть несколько вещей неправильно. Когда я извлекаю интерфейс INotifyPropertyChanged и метод OnPropertyChanged(), все еще работает отлично (почему ?! Это не должно, верно?)

Кроме того, когда я добавить точку останова на сеттера собственности BackgroundColor в моем классе MyStyle, свойство не обновляется. Он должен обновлять, потому что я связываю его с помощью следующей строки: b.Path = new PropertyPath(nameof(BackgroundColor));

Мои вопросы:

  1. Почему это все еще работает, когда я удалить все вещи INotifyPropertyChanged
  2. Почему не свойство BackgroundColor моего обновления объекта, когда я изменить цвет (почему он не попал в сеттер точку останова)

У меня есть следующие ViewModel:

public class BoxViewModel : INotifyPropertyChanged 
{ 
    private string _backgroundcolor; 

    public string Description { get; set; } 
    public string BackgroundColor 
    { 
     get 
     { 
      return _backgroundcolor; 
     } 
     set 
     { 
      _backgroundcolor = value; 
      OnPropertyChanged(); 
     } 
    } 

    /// <summary> 
    /// Occurs when [property changed]. 
    /// </summary> 
    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Который работает со следующей моделью:

public class Box : MyStyle 
{ 
    Canvas _label; 
    Border _border; 
    string _description; 
    BoxViewModel vm; 

    public override void Draw(Canvas label) 
    { 
     _label = label; 
     _border = new Border(); 

     _border.BorderBrush = BorderColorBrush; 
     _border.Background = BackgroundColorBrush; 

     _border.Width = Width; 
     _border.Height = Height; 

     // 

     _border.DataContext = vm; 

     Binding b = new Binding(); 
     b.Source = vm; 
     b.Path = new PropertyPath(nameof(BackgroundColor)); 
     b.Mode = BindingMode.TwoWay; 
     b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 

     BindingOperations.SetBinding(_border, Border.BackgroundProperty, b); 

     label.Children.Add(_border); 

    } 

    internal override void AddInputs(ItemsControl inputPanel) 
    { 
     vm = new BoxViewModel() 
     { 
      Description = _description, 
      BackgroundColor = BackgroundColor     
     }; 

     inputPanel.Items.Add(vm); 
    } 
} 

И тогда MyStyle это абстрактный класс с кучей свойств, как BackgroundColor один:

public abstract class MyStyle 
{ 
    string _BackgroundBrush; 
    string _BackgroundColor; 
    ..... 
    public string BorderColor 
    { 
     get { return _BorderColor; } 
     set 
     { 
      _BorderColor = value; 
      BorderColorBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value != null ? BorderColor : "#FFFFFFFF")); 
     } 
    } 
    public SolidColorBrush BorderColorBrush { get; set; } 


    public string BackgroundColor { 
     get { return _BackgroundColor; } 
     set { 
      _BackgroundColor = value; 
      BackgroundColorBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value != null ? BackgroundColor : "#FFFFFFFF")); 
     } 
    } 
    public SolidColorBrush BackgroundColorBrush { get; set; } 

    ..... 
} 

Редактировать

Он обновляет свойство BoxViewModel.BackgroundColor, и эти сеттеры и получатели вызывают, когда цвет i s изменено. Тем не менее ничего не происходит с MyStyle.BackgroundColor не меняется. Есть ли у него что-то делать с контекстом данных или с привязывающим свойством или чем-то еще? И строка BackgroundColor, и BackgroundColors из класса mystyle должны измениться.

+1

'public class Box: MyStyle' wat – Will

+0

@ Извините, я переименовал его для целей вопроса, но сделал орфографическую ошибку. Стиль абстрактного класса должен быть MyStyle (со свойствами фона) – Markinson

+0

Я новичок в Binding и WPF, поэтому у меня есть только предположение: вы привязываете View и класс Box. Нет никаких привязок к классу ViewModel. Возможно, вам следует создать экземпляр класса Box в вашей ViewModel, а не экземпляр из ViewModel в классе Box !? ViewModel управляет всем. Затем получить данные из класса Box и привязать его к ViewModel. Надеюсь, это не совсем так. : D –

ответ

2

Это свойство является особенностью механизма привязки WPF. Он обнаруживает, что у вас несколько элементов управления, привязанных к одному экземпляру источника данных (VM), и по крайней мере одно из этих привязок находится в режиме TwoWay. Когда привязка обновляет свойство source, механизм привязки автоматически обновляет другие связанные элементы управления без необходимости уведомления.

INotityPropertyChanged будет необходим для изменений, которые не происходят с помощью привязки (изменения, выполняемые в коде).

Я проверил это с помощью простого приложения WPF, которое имеет два текстовых поля, привязанных (в двух направлениях) к модели представления POCO без реализации INPC. Обновление любого текстового поля изменяет содержимое другого, без видимого механизма уведомления.

+1

Кстати, я много лет использую WPF и никогда не замечал этого поведения. Очень приятно найти. –

+0

Изменяется ли ваш ответ, если я скажу, что каждый бокс имеет свой собственный источник данных? Я никогда не рисую несколько ящиков из одного объекта, я всегда рисую только один из одного объекта с одним источником данных (потому что ящики являются экземплярами десериализации XML). – Markinson

+1

Нет. Я имею в виду поле и соответствующий ColorPicker –

2

Посмотрите на this.

Извините, так долго, чтобы ответить, на самом деле вы столкнулись с другим скрытым аспектом WPF, вот оно данные WPF, обязательного двигателем будет данные связываются с PropertyDescriptor экземпляра, который оборачивает свойство источника, если исходный объект является простым CLR и не реализует интерфейс INotifyPropertyChanged. И механизм привязки данных попытается подписаться на событие с измененным свойством через метод PropertyDescriptor.AddValueChanged(). И когда элемент данных, привязанный к целевым данным, изменит значения свойств, механизм привязки данных вызовет метод PropertyDescriptor.SetValue() для переноса измененного значения обратно в исходное свойство и одновременно будет вызывать событие ValueChanged для уведомления других подписчиков (в данном случае, остальные подписчики будут TextBlocks в ListBox.

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

Надеюсь, что это немного облегчит ситуацию.

Таким образом, в основном вы можете это сделать, если это простой объект CLR.

Смежные вопросы