简体   繁体   中英

Binding to dependency property in usercontrol

I have a UserControl that contains a ListBox and I want to track the SelectedItems of that listbox. The UserControl has a DP "SelectedItemsList" that is defined like this

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. 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.

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

My problem is, that the DP SelectedItemsList never gets updated. The PropertyChangeCallback "OnSelectedItemsChanged" of the DP is only triggered when I initially load the lists content. The value of the SelectedItemsList is always 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.

What am I missing here?

Thanks,

Edit (2015-09-10): Thank you all for your comments. 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 ).

 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. 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:

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:

  <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

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.

And in the view's 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. 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. 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.

And don't use the PropertyChangeCallback in your DP: Changing the SelectedItemsList if the SelectedItemsListProperty has changed makes no sense. (Usually the former is a wrapper property of the latter.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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