Обновить привязку без DependencyProperty - PullRequest
0 голосов
/ 29 марта 2011

У меня есть много существующих бизнес-объектов со многими свойствами и коллекциями, с которыми я хочу связать пользовательский интерфейс.Использование DependencyProperty или ObservableCollections внутри этих объектов не вариант.Поскольку я точно знаю, когда я изменяю эти объекты, я хотел бы иметь механизм для обновления всех элементов управления пользовательского интерфейса, когда я делаю это.Кроме того, я также не знаю, какие элементы управления пользовательского интерфейса связываются с этими объектами и с какими свойствами.

Вот упрощенный код того, что я пытался сделать на данный момент:

public class Artikel
{
   public int MyProperty {get;set;}
}

public partial class MainWindow : Window
{
    public Artikel artikel
    {
        get { return (Artikel)GetValue(artikelProperty); }
        set { SetValue(artikelProperty, value); }
    }

    public static readonly DependencyProperty artikelProperty =
        DependencyProperty.Register("artikel", typeof(Artikel), typeof(MainWindow), new UIPropertyMetadata(new Artikel()));

    public MainWindow()
    {
        InitializeComponent();
        test.DataContext = this;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
         artikel.MyProperty += 1;
         // What can I do at this point to update all bindings?
         // What I know at this point is that control test or some of it's 
         // child controls bind to some property of artikel.
    }
}
<Grid Name="test">
    <TextBlock Text="{Binding Path=artikel.MyProperty}" />
</Grid>

То есть я пытался упаковать свой объект в DependencyProperty и пытался вызвать UpdateTarget для этого, но не удалось.

Что я мог сделать, чтобы обновить соответствующие элементы управления пользовательского интерфейса?

Надеюсь, я достаточно хорошо описал свою ситуацию.

Ответы [ 3 ]

8 голосов
/ 29 марта 2011

Использование INotifyPropertyChanged является хорошей альтернативой DependencyProperties.

Если вы реализуете интерфейс, вы можете вызвать событие PropertyChanged с параметром null, чтобы уведомить пользовательский интерфейс об изменении всех свойств.

1 голос
/ 29 марта 2011

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

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

Вам не нужно использовать свойства зависимостей для этого.Свойства зависимостей необходимы только для target привязки, то есть элементов управления в пользовательском интерфейсе.Ваши объекты модели представления являются источником;им нужно только реализовать INotifyPropertyChanged.

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

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

public string Foo
{
   get { return _Model.Foo; }
   set
   {
      if (value != _Model.Foo)
      {
         _Model.Foo = value;
         OnPropertyChanged("Foo");
      }
   }
}

Но если, как вы заявили, вы знаете, когда обновляются объекты, и выпросто хотите отправить обновления в пользовательский интерфейс, вы можете реализовать свойства только для чтения, а когда базовая модель данных будет обновлена, заставить модель представления поднять PropertyChanged со свойством PropertyName аргументов события, равным нулю, чтоговорит привязке: «Каждое свойство этого объекта изменилось; обновите все цели привязки».

1 голос
/ 29 марта 2011

(Я предполагаю, что вы также не можете добавить INotifyPropertyChanged к своим бизнес-объектам, и что вы не хотите добавлять еще один слой "представления модели данных" для объектов-оболочек, таких как MVVM.)

Вы можете вручную обновить связанные свойства из их источника данных, вызвав BindingExpression.UpdateTarget ().

myTextBlock.GetBindingExpression(TextBlock.TextProperty).UpdateTarget();

Чтобы обновить все привязки в элементе управления или окне, вы можете использовать что-то вроде этого:

using System.Windows.Media;
...
static void UpdateBindings(this DependencyObject obj)
{
    for (var i=0; i<VisualTreeHelper.GetChildrenCount(obj); ++i)
    {
        var child = VisualTreeHelper.GetChild(obj, i);
        if (child is TextBox)
        {
            var expression = (child as TextBox).GetBindingExpression(TextBox.TextProperty);
            if (expression != null)
            {
                expression.UpdateTarget();
            }
        }
        else if (...) { ... }
        UpdateBindings(child);        
    }
}

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

В качестве сноски вы также можете использовать BindingExpression.UpdateSource (), если вы хотите явно выполнить обратную запись в источник данных.Элементы управления обычно делают это в любом случае, когда их значение изменяется или когда они теряют фокус, но вы управляете этим и делаете это вручную с помощью {Binding Foo, UpdateSourceTrigger=Explicit}.

...