XAML 如何绑定到非ObservableCollection?

nxowjjhe  于 2023-10-14  发布在  其他
关注(0)|答案(2)|浏览(120)

有没有一种方法可以直接绑定到模型中的一个Collection,并手动告诉WPF绑定需要刷新,而不必在视图模型中为它创建一个ObservableCollection?

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

Position是我的模型,是国际象棋库的一部分,PossibleMoves是其中的一个Collection。我不想实现INotifyProperty更改或把ObservableCollections在一个独立的优化库。
我想避免在每次位置更新时将PossibleMoves复制到ObservableCollection中。数据绑定在初始化时工作,但如果我也可以在视图模型中随意刷新绑定,那将很方便。
从视图模型调用OnNotifyPropertyChanged(“Position.PossibleMoves”)不起作用,因为对集合本身的引用不会更改。

qkf9rpyu

qkf9rpyu1#

您可以通过使用附加行为将处理程序绑定到视图模型中触发的事件来实现这一点。但是你不能直接绑定到事件,所以你必须把它们 Package 在一个类中,如下所示:

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;}}
}

接下来,创建一个附加行为,该行为向该事件注册委托示例,并强制列表框刷新其绑定:

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(),它将强制更新列表框。
这是可行的,但实际上是把方钉敲进圆孔里。如果我是你,我会尽我所能尝试在你的视图模型中做适当的集合更改通知。我理解你想把ObservableCollection排除在你的模型之外,但是有一些方法可以自动代理更改通知(例如:Castle DynamicProxy)。

ktca8awb

ktca8awb2#

您需要从Position类内部为PossibleMoves通知PropertyChange,或者创建一个委托给Position.PossibleMoves的属性并通知它。

相关问题