wpf - 如何绑定(bind)到非 ObservableCollection?

标签 wpf xaml data-binding mvvm observablecollection

有没有办法直接绑定(bind)到模型中的集合并手动告诉 WPF 绑定(bind)需要刷新,而不必在 View 模型中为其创建 ObservableCollection?

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

Position 是我的模型,是国际象棋库的一部分,PossibleMoves 是其中的一个集合。我不想实现 INotifyProperty 更改或将 ObservableCollections 放在独立的优化库中。

我想避免在每次更新位置时将 PossibleMoves 复制到 ObservableCollection 中。数据绑定(bind)在初始化时起作用,但如果我也可以在 View 模型中随意刷新绑定(bind),那将很方便。

从 View 模型调用 OnNotifyPropertyChanged("Position.PossibleMoves") 不起作用,因为对集合本身的引用不会改变。

最佳答案

您可以通过使用附加行为将处理程序绑定(bind)到在 View 模型中触发的事件来做到这一点。你不能直接绑定(bind)到事件,所以你必须将它们包装在一个类中,如下所示:

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

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

现在将它的一个实例添加到您的 View 模型中:
public class MyViewModel
{
    public IList<string> Items { get; set; }

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

接下来创建一个附加行为,向该事件注册一个委托(delegate)实例并强制列表框刷新其绑定(bind):
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;
    }
}

最后将其附加到 xaml 中的列表框:
<ListBox ItemsSource="{Binding Items}"
    local:RefreshBehavior.Refresher="{Binding Refresher}"/>

就是这样。调用 Refresher.DoRefresh()在您的 View 模型中,它将强制更新列表框。

这行得通,但它实际上是将一个方形钉子锤入一个圆孔。如果我是你,我会尽我所能尝试在你的 View 模型中做正确的集合更改通知。我了解您希望将 ObservableCollection 排除在模型之外,但有一些方法可以自动代理更改通知(例如 CaSTLe DynamicProxy)。

关于wpf - 如何绑定(bind)到非 ObservableCollection?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21491420/

相关文章:

.net - 是否有 WPF XAML 用于统一拟合但恒定的 StrokeThickness

c# - 如何绑定(bind)到 CheckedListBox.SelectedItems.Count

.net - 如何在同一个 WPF 控件上绑定(bind)多个属性?

.net - WPF 的三大博客是什么?

c# - 如何将作为参数传递的 KeyValuePair 转换为 Command_Executed?

c# - WPF AlternateContent 不工作

c# - DependencyProperty 的 PropertyChangedCallback 忽略延迟绑定(bind)

javascript - Angular 2 App 中项目之间没有逗号的数据绑定(bind)

c# - 禁用选择或聚焦列表框项目

c# - 打开包含大量项目的组合框时 wpf UI 卡住