2016-10-20 53 views
0

我有一個MVVM應用程序,我想將3個集合綁定在一起。在視圖中我有ItemsControl與TimeBoxes(只有文本框與依賴項屬性時間)。WPF綁定3集合在一起

<Window x:Class="Scoreboard.View.MainWindow" 
    ... 
    <ItemsControl ItemsSource="{Binding TimeBoxes}"/> 
    ... 
</Window> 

隨着後面的代碼

public class Mainwindow 
{ 
    //... 
    var Timeboxes = new ObservableCollection<TimeBox>(); 
} 

在模式,我想有一個時間集合。

public class GameModel 
{ 
    var Times = new ObservableCollection<Time>(); 
    // Don't know if this is how it should be 
} 

然後我有輸出中的另一個窗口,類同瀏覽主窗口,但ItemsControl的持有國界的,而不是時間盒。

<Window x:Class="Scoreboard.Display.DisplayWindow" 
    ... 
    <ItemsControl ItemsSource="{Binding Borders}"/> 
    ... 
</Window> 

它應該做的是:一旦點擊查看中的一個按鈕(MainWindow)一TimeBoxTimeBoxes集合創建。 Time的那個TimeBox綁定到TimeTimesGameModel。並且Time也被綁定到輸出(顯示)WindowBorders中新的Border(我有TimeToStringConverter)的內容(標籤)。當TimeGameModel達到零時,其實例將從所有集合中刪除。我的問題是我不知道如何將集合中的項目綁定到另一個集合的項目。爲簡單起見,省略ViewModel。

總結我想動態綁定TimeBoxTimeTimeBorder的在1內容:1:1的比例。

回答

2

在這裏,您有一個測試解決方案,可將與2 ObservableCollection綁定在一起。當一個項目被添加或從一個集合中刪除時,另一個被更新。 Bind方法返回IDisposable,因此當您處置它時,自動更新將終止。 這適用於2個相同通用類型的集合。如果您需要處理不同類型的集合的方法,你應該實現的方法與喜歡的註釋方法簽名:

[TestClass] 
public class BindTwoObservableCollections_test 
{ 
    [TestMethod] 
    public void BindTwoObservableCollections() 
    { 
     var c1 = new ObservableCollection<int>(); 
     var c2 = new ObservableCollection<int>(); 

     c1.Add(1); 
     Assert.AreEqual(0, c2.Count); 

     var subscription = CollectionHelper.Bind(c1, c2); 

     c1.Add(2); 
     Assert.AreEqual(1, c2.Count); 
     Assert.AreEqual(2, c2[0]); 

     c2.Add(3); 
     Assert.AreEqual(3, c1.Count); 
     Assert.AreEqual(3, c1[2]); 

     c2.Remove(2); 
     Assert.AreEqual(2, c1.Count); 

     subscription.Dispose(); 

     c2.Remove(3); 
     Assert.AreEqual(2, c1.Count); 
    } 
} 

public static class CollectionHelper 
{ 
    public static IDisposable Bind<T>(
     ObservableCollection<T> c1, 
     ObservableCollection<T> c2) 
    { 
     var fromC1Subscription = InternalBind(c1, c2); 
     var fromC2Subscription = InternalBind(c2, c1); 

     return new Disposable(() => 
     { 
      fromC1Subscription?.Dispose(); 
      fromC2Subscription?.Dispose(); 
     }); 
    } 

    private static IDisposable InternalBind<T>(
     ObservableCollection<T> from, 
     ObservableCollection<T> to) 
    { 
     NotifyCollectionChangedEventHandler onFromChanged = 
      (s, e) => 
      { 
       switch (e.Action) 
       { 
        case NotifyCollectionChangedAction.Add: 
         foreach (T added in e.NewItems) 
          if (!to.Contains(added)) 
           to.Add(added); 
         break; 

        case NotifyCollectionChangedAction.Remove: 
         foreach (T removed in e.OldItems) 
          to.Remove(removed); 
         break; 

        //other cases... 

        default: 
         break; 
       } 
      }; 

     from.CollectionChanged += onFromChanged; 

     return new Disposable(() => { from.CollectionChanged -= onFromChanged; }); 
    } 

    //public static IDisposable Bind<T1, T2>(
    // ObservableCollection<T1> c1, 
    // ObservableCollection<T2> c2, 
    // Func<T1, T2> converter1, 
    // Func<T2, T1> converter2) 
    //{ 
    // todo... 
    //} 
} 

public class Disposable : IDisposable 
{ 
    public Disposable(Action onDispose) 
    { 
     _onDispose = onDispose; 
    } 

    public void Dispose() 
    { 
     _onDispose?.Invoke(); 
    } 

    private Action _onDispose; 
} 

顯然,如果你需要綁定C1,C2和C3,你寫的:

CollectionHelper.Bind(c1, c2); 
CollectionHelper.Bind(c2, c3); 

這就夠了。

+0

謝謝你,這是一個甜蜜的解決方案。我非常專注於約束力,忘記了通知:D – Korhak

+0

「我知道那種感覺,兄弟」;) –