WPF将3个集合绑定在一起
本文关键字:绑定 在一起 集合 3个 WPF | 更新日期: 2023-09-27 18:14:13
我有一个MVVM应用程序,我想将3个集合绑定在一起。在视图中,我有ItemsControl与TimeBoxes(只是TextBoxes与依赖属性时间)。
<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
)中的按钮时,TimeBox
将在TimeBoxes
集合中创建。TimeBox
中的Time
在GameModel
中绑定到Times
中的新Time
。并且Time
也绑定到输出(显示)Window
的Borders
中的新Border
(我为此使用TimeToStringConverter
)的内容(标签)。当GameModel
中的Time
达到零时,它的实例将从所有集合中删除。我的问题是我不知道如何将一个集合中的一个项目绑定到另一个集合的一个项目。为简单起见,省略了ViewModel。
总而言之,我想动态绑定TimeBox
到Time
, Time
到Border
的内容以1:1:1的比例
这里有一个CollectionHelper
的测试解决方案,它将两个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);
这就够了