【问题标题】:Binding to dependency property in usercontrol绑定到用户控件中的依赖属性
【发布时间】:2015-09-09 14:49:27
【问题描述】:

我有一个包含 ListBox 的 UserControl,我想跟踪该列表框的 SelectedItems。 UserControl 有一个这样定义的 DP“SelectedItemsList”

public static DependencyProperty SelectedItemsListProperty = DependencyProperty.Register(
  "SelectedItemsList",
  typeof (IList),
  typeof (MyListControl),
  new FrameworkPropertyMetadata(null, 
    OnSelectedItemsChanged));

在列表框的项目“SelectionChanged”事件中,我想将选定的项目保存到 DP。每当我更改列表框中的选择时都会触发此操作。

private void OnItemSelectionChanged(object sender, SelectionChangedEventArgs e)
{
  SelectedItemsList = this.myListBox.SelectedItems;
}

在包含“MyListControl”的视图中,我创建了一个与要使用所选项目的视图模型的绑定。

 <controls:MyListControl 
  Source="{Binding SomeItemsList, UpdateSourceTrigger=PropertyChanged}"
  SelectedItemsList="{Binding SelectedItems, UpdateSourceTrigger=PropertyChanged}"/>

我的问题是,DP SelectedItemsList 永远不会更新。仅当我最初加载列表内容时才会触发 DP 的 PropertyChangeCallback "OnSelectedItemsChanged"。 SelectedItemsList 的值始终为 null。

我知道这个问题类似于Dependency property callback does not work,但那里发布的答案并不能解决我的问题。

我在这里错过了什么?

谢谢,

编辑(2015-09-10): 谢谢大家的cmets。我找到了适合我需要的解决方案:

首先,我创建了一个自定义列表框控件,该控件在依赖属性中提供所选项目的列表(非常类似于Select multiple items from a DataGrid in an MVVM WPF project)。

 public class CustomListBox : ListBox
 {
    public static readonly DependencyProperty SelectedItemsListProperty =
         DependencyProperty.Register("SelectedItemsList",
         typeof (IList),
         typeof (CustomListBox),
         new PropertyMetadata(null));

    public CustomListBox()
    {
       SelectionChanged += OnSelectionChanged;
    }

   public IList SelectedItemsList
   {
       get { return (IList)GetValue(SelectedItemsListProperty); }
       set { SetValue(SelectedItemsListProperty, value); }
   }

   void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
   {
      this.SelectedItemsList= new ArrayList(this.SelectedItems);
   }   
  }   

我对“新 ArrayList”部分还不满意,但如果我想在我的视图模型的属性设置器中检查是否相等,则 SelectedItemsList 不能作为 SelectedItems 的引用。以前的值和新的值总是相同的。

然后我将用户控件“MyListControl”的项目选择部分简化为依赖属性本身:

public static DependencyProperty SelectedItemsProperty =  DependencyProperty.Register(
  "SelectedItems",
  typeof (IList),
  typeof (MyListControl),
  new FrameworkPropertyMetadata(null));


public IList SelectedItems
{
  get
  {
    return (IList)GetValue(SelectedItemsProperty);
  }
  set
  {
    SetValue(SelectedItemsProperty, value);
  }
}

并修改了MyListControl的xaml:

  <controls:CustomListBox  
       SelectionMode="Extended" 
       ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:MyListControl}},
       Path=Source, UpdateSourceTrigger=PropertyChanged}"           
       SelectedItemsList="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:MyListControl}},
       Path=SelectedItems, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
       >

我的 ViewModel 中的属性看起来像

public IList SelectedObjects
{
  get { return _selectedObjects; }
  set { if (this._selectedObjects != value)
        {
          this._selectedObjects = value;
          OnPropertyChanged(SelectedObjectsProperty);
        }
       }
 }

此属性的类型是 IList 很重要,否则 setter 中的值将始终为 null。

在视图的 xaml 中

<controls:MyListControl
  Source="{Binding CurrentImageList, UpdateSourceTrigger=PropertyChanged}"
  SelectedItems="{Binding SelectedObjects, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
 />

【问题讨论】:

  • 当我添加“SelectedItemsList = null;”在“OnItemSelectionChanged”中的常规集之前,propertychangecallabck 被触发(对于两个集),但与我的 ViewModel 的绑定仍然始终包含“null”。

标签: wpf binding user-controls dependency-properties


【解决方案1】:

我今天遇到了同样的问题,不幸的是,当您为 SelectedItemsList 分配一个值时,WPF 似乎解除了它的绑定。为了修复它,我更新了绑定项中的值。我知道这不是世界上最好的解决方案,但对我来说它有效。 在这种情况下,代码如下所示:

private void OnItemSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    this.SetPropertyValue(
    this.GetBindingExpression(SelectedItemsListProperty), 
                this.myListBox.SelectedItems);
}


    private void SetPropertyValue(BindingExpression bindingExpression, object value)
    {
        string path = bindingExpression.ParentBinding.Path.Path;

        var properties = new Queue<string>(
            path.Split(
                new[]
                    {
                        '.'
                    }).ToList());

        this.SetPropertyValue(bindingExpression.DataItem, bindingExpression.DataItem.GetType(), properties, value);
    }



    private void SetPropertyValue(object destination, Type type, Queue<string> properties, object value)
    {
        PropertyInfo property = type.GetProperty(properties.Dequeue());

        if (property != null && destination != null)
        {
            if (properties.Count > 0)
            {
                this.SetPropertyValue(property.GetValue(destination), property.PropertyType, properties, value);
            }
            else
            {
                property.SetValue(destination, value);
            }
        }
    }

【讨论】:

    【解决方案2】:

    您需要将 Listbox 的 SelectedItems 绑定到 DP SelectedItemsList 以将用户选择传播到 DP。然后,您已经拥有的绑定会将更改传递给视图模型,但我认为您将需要一个绑定模式“双向”而不是 UpdateSourceTrigger。

    并且不要在您的 DP 中使用 PropertyChangeCallback:如果 SelectedItemsListProperty 已更改,则更改 SelectedItemsList 没有任何意义。 (通常前者是后者的封装属性。)

    【讨论】:

    • 我只是使用 PropertyChangeCallback 来设置断点以查看是否发生任何更改。
    • 列表框没有 SelectedItems 属性的公共设置器。所以我不能直接绑定到它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2013-02-11
    • 1970-01-01
    • 2012-03-29
    相关资源
    最近更新 更多