在 SetValue 之后从 DependencyProperty 在 ViewModel 中获取 null

Posted

技术标签:

【中文标题】在 SetValue 之后从 DependencyProperty 在 ViewModel 中获取 null【英文标题】:Getting null in ViewModel from DependencyProperty after SetValue 【发布时间】:2021-11-25 22:14:06 【问题描述】:

我有这个带有 SelectedItems 属性的扩展 ListBox,以便能够在将 SelectionMode 设置为 Extended 时获取所选项目。

public class BindableMultiSelectListBox : ListBox

    public static new readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof(IList), typeof(BindableMultiSelectListBox),
            new PropertyMetadata(default(IList)));

    public new IList SelectedItems
    
        get => (IList)GetValue(SelectedItemsProperty);
        set => throw new Exception("This property is read-only. To bind to it you must use 'Mode=OneWayToSource'.");
    

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    
        base.OnSelectionChanged(e);
        SetValue(SelectedItemsProperty, base.SelectedItems);
    

我在这样的视图中使用它:

<usercontrols:BindableMultiSelectListBox SelectedItems="Binding SelectedDogs, Mode=OneWayToSource" ItemsSource="Binding Dogs" SelectionMode="Extended"/>

并绑定到我的 viewModel 中的 ObservableCollection:

private ObservableCollection<string> _selectedDogs;

public ObservableCollection<string> SelectedDogs

    get
    
        return _selectedDogs;
    
    set
    
        _selectedDogs = value;
        OnPropertyChanged(nameof(SelectedDogs));
    

当我调试 OnSelectionChanged base.SelectedItems 具有预期的选定值,但是当 SelectedDogs 设置器被击中时,该值为 null!

我在这里做错了什么?

【问题讨论】:

SelectedItemsProperty 依赖属性的默认值为default(IList),即null,所以当控件第一次初始化时,SelectedItems 为空。绑定应该将该 null 推送到视图模型。我对BindableMultiSelectListBox 的了解不够多,不知道是什么原因导致它的OnSelectionChanged 处理程序被调用,但您是否验证过它 调用过?放置断点。 OnSelectionChanged 应该被调用,然后你的视图模型应该用非空值更新。这没有发生吗? Observablecollection 不是 ilist。 @Joe BindableMultiSelectListBox 只是一个扩展的列表框。我在我的视图模型的设置器中设置了断点,当我选择任何值时,它会在启动时以 null 值命中以及 null 命中。与安迪暗示的一些选角问题有关吗? @Andy ObservableCollection 继承自实现 IList 的 Collection。这仍然是个问题吗? 【参考方案1】:

将 viewModel 中的 SelectedDogs 属性从 ObservableCollection&lt;string&gt; 更改为 IList 解决了这个问题。

在实践中似乎没有什么不同,但是如果我希望能够在我的 viewModel 中指定 ObservableCollection 怎么办?为什么 ObservableCollection 不起作用?它确实继承自实现了IListCollection

【讨论】:

【参考方案2】:

目标属性应该绑定到源属性。

在视图模型中初始化源集合:

public ObservableCollection<string> SelectedDogs  get;  = new ObservableCollection<string>();

...并在控件中实现同步:

protected override void OnSelectionChanged(SelectionChangedEventArgs e)

    base.OnSelectionChanged(e);
    if (SelectedItems != null)
    
        foreach (var removed in e.RemovedItems)
            SelectedItems.Remove(removed);
        foreach (var added in e.AddedItems)
            SelectedItems.Add(added);
    

XAML:

... SelectedItems="Binding SelectedDogs"

如果要设置源属性,则应在控件中初始化集合。

【讨论】:

以上是关于在 SetValue 之后从 DependencyProperty 在 ViewModel 中获取 null的主要内容,如果未能解决你的问题,请参考以下文章

QSettings setvalue 方法将 QVariant 数据类型写入 Windows 注册表

带有来自服务的数据的 Angular FormArray setValue

InvalidFirebaseData',原因:'(setValue:)

将列添加到 CSV Windows PowerShell

为啥 .setValue() 在 for 循环中跳过列?

依赖属性