简体   繁体   English

绑定到usercontrol中的依赖项属性

[英]Binding to dependency property in usercontrol

I have a UserControl that contains a ListBox and I want to track the SelectedItems of that listbox. 我有一个包含一个ListBox的UserControl,我想跟踪该列表框的SelectedItems。 The UserControl has a DP "SelectedItemsList" that is defined like this UserControl有一个DP“ SelectedItemsList”,其定义如下

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

In the listbox' Item "SelectionChanged" event, I want to save the selected items to the DP. 在列表框的项目“ SelectionChanged”事件中,我想将所选项目保存到DP。 This is triggered whenever I change the selection in the listbox. 每当我更改列表框中的选择时,都会触发此操作。

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

In my view that contains the "MyListControl" I create a binding to my viewmodel that want to use the selected items. 在包含“ MyListControl”的视图中,我创建了要使用所选项目的视图模型的绑定。

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

My problem is, that the DP SelectedItemsList never gets updated. 我的问题是,DP SelectedItemsList永远不会更新。 The PropertyChangeCallback "OnSelectedItemsChanged" of the DP is only triggered when I initially load the lists content. DP的PropertyChangeCallback“ OnSelectedItemsChanged”仅在我最初加载列表内容时触发。 The value of the SelectedItemsList is always null. SelectedItemsList的值始终为null。

I am aware that this question is similar to Dependency property callback does not work , but the answers posted there do not solve my problem. 我知道这个问题类似于Dependency属性回调不起作用 ,但是在那里发布的答案不能解决我的问题。

What am I missing here? 我在这里想念什么?

Thanks, 谢谢,

Edit (2015-09-10): Thank you all for your comments. 编辑(2015-09-10):谢谢大家的评论。 I found a solution that fits my needs: 我找到了适合我需求的解决方案:

First of all I created a custom listbox control that provided the list of selected items in a dependency property (very similar to Select multiple items from a DataGrid in an MVVM WPF project ). 首先,我创建了一个自定义列表框控件,该控件在依赖项属性中提供了选定项目的列表(非常类似于从MVVM WPF项目中从DataGrid中选择多个项目 )。

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

I am not happy yet with the "new ArrayList"-part, but if in my viewmodel's property setter I want to check for equality, SelectedItemsList can not be a reference of SelectedItems. 我对“ new ArrayList”部分还不满意,但是如果在我的视图模型的属性设置器中我想检查是否相等,则SelectedItemsList不能是SelectedItems的引用。 The previous and the new value would always be the same. 以前的值和新的值将始终相同。

Then I reduced the item selection parts of my UserControl "MyListControl" simply to the dependency property itself: 然后,将UserControl“ 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);
  }
}

and modified the xaml of the MyListControl: 并修改了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}"
       >

The property in my ViewModel looks like 我的ViewModel中的属性看起来像

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

It was important that the type of this property is IList, otherwise the value in the setter would always be null. 此属性的类型为IList非常重要,否则设置器中的值将始终为null。

And in the view's xaml 在视图的xaml中

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

I just had the same problem today, unfortunately, when you are assigning to SelectedItemsList a value, WPF seems to unbind it. 不幸的是,今天我遇到了同样的问题,当您为SelectedItemsList分配一个值时,WPF似乎将其取消绑定。 To fix it, I update the value in the binded item. 为了解决这个问题,我更新了绑定项目中的值。 I know that it is not the best solution in the world but for me it works. 我知道这不是世界上最好的解决方案,但对我而言,它是有效的。 In this case the code would looked like this: 在这种情况下,代码如下所示:

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

You need to bind your Listbox' SelectedItems to the DP SelectedItemsList to propagate the user selection to the DP. 您需要将列表框的SelectedItems绑定到DP SelectedItemsList,以将用户选择传播到DP。 The binding you already have will then pass the changes on to the viewmodel, but I think you will need a binding mode 'twoway' instead of UpdateSourceTrigger. 然后,您已经拥有的绑定将把更改传递给viewmodel,但是我认为您将需要绑定模式“双向”而不是UpdateSourceTrigger。

And don't use the PropertyChangeCallback in your DP: Changing the SelectedItemsList if the SelectedItemsListProperty has changed makes no sense. 并且不要在DP中使用PropertyChangeCallback:如果SelectedItemsListProperty发生了更改,则更改SelectedItemsList是没有意义的。 (Usually the former is a wrapper property of the latter.) (通常,前者是后者的包装器属性。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM