2014-01-31 2 views
1

Есть ли способ привязать непосредственно к коллекции в модели и вручную сообщить WPF, что привязка нуждается в обновлении без необходимости создания ObservableCollection для него в viewmodel?Как я могу привязать к не ObservableCollection?

<ListBox ItemsSource="{Binding Position.PossibleMoves}"> 
... 
</ListBox> 

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

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

Вызов OnNotifyPropertyChanged ("Position.PossibleMoves") из режима просмотра не работает, потому что ссылка на саму коллекцию не изменяется.

+1

Возможный дубликат [Как принудительно привязать WPF для обновления?] (Http://stackoverflow.com/questions/5676202/how-to-force-a-wpf-binding-to-refresh) – Steve

+0

К сожалению, нет, это решение предназначено для обновления привязки с точки зрения, вызывая GetBindingExpression (dp) .UpdateTarget для элемента FrameworkElement. – FreddyFlares

+0

Является ли ListBox не элементом FrameworkElement? – Steve

ответ

4

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

public class Refresher 
{ 
    public delegate void RefreshDelegate(); 
    public event RefreshDelegate Refresh; 

    public void DoRefresh() 
    { 
     if (this.Refresh != null) 
      this.Refresh(); 
    } 
} 

Теперь добавьте экземпляр, что в вашей модели представления:

public class MyViewModel 
{ 
    public IList<string> Items { get; set; } 

    private Refresher _Refresher = new Refresher(); 
    public Refresher Refresher {get {return this._Refresher;}} 
} 

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

public static class RefreshBehavior 
{ 
    public static readonly DependencyProperty RefresherProperty = DependencyProperty.RegisterAttached(
     "Refresher", 
     typeof(Refresher), 
     typeof(RefreshBehavior), 
     new PropertyMetadata(null, OnRefresherChange)); 

    public static void SetRefresher(DependencyObject source, Refresher value) 
    { 
     source.SetValue(RefresherProperty, value); 
    } 

    public static Refresher GetRefresher(DependencyObject source) 
    { 
     return (Refresher)source.GetValue(RefresherProperty); 
    } 

    private static void OnRefresherChange(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     Refresher.RefreshDelegate handler =() => 
     { 
      var listBox = d as ListBox; 
      listBox.Items.Refresh(); 
     }; 

     if (e.NewValue != null) 
      (e.NewValue as Refresher).Refresh += handler; 
     if (e.OldValue != null) 
      (e.OldValue as Refresher).Refresh -= handler; 
    } 
} 

и, наконец, приложить его к ListBox в XAML:

<ListBox ItemsSource="{Binding Items}" 
    local:RefreshBehavior.Refresher="{Binding Refresher}"/> 

Всё. Вызовите Refresher.DoRefresh() в вашей модели просмотра, и это заставит обновление списка.

Это работает, но это действительно забивает квадратный штифт в круглое отверстие. Если бы я был вами, я бы сделал все возможное, чтобы попытаться сделать соответствующее уведомление об изменении коллекции в вашей модели. Я понимаю, что вы хотите оставить ObservableCollection вне своей модели, но есть способы автоматического уведомления об изменении прокси (например, Castle DynamicProxy).

+1

Это круто, я никогда не думал об упаковке события внутри класса, это можно использовать во всех сценариях. – FreddyFlares

+0

Другое приложение вызывает всплывающие диалоговые окна из модели представления. –

0

Вам необходимо NotifyPropertyИзменить для Возможных перемещений из класса Position или создать свойство, которое делегирует Position.PossibleMoves и уведомляет об этом.

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