2016-10-20 54 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

“我知道那种感觉,兄弟”;) –