简体   繁体   中英

TwoWay Binding to ListBox SelectedItem on more than one list box in WPF

I have a scenario where I have a globally available Properties window (similar to the Properties window in Visual Studio), which is bound to a SelectedObject property of my model. I have a number of different ways to browse and select objects, so my first attempt was to bind them to SelectedObject directly. For example:

<ListBox ItemsSource="{Binding ActiveProject.Controllers}" 
SelectedItem="{Binding SelectedObject, Mode=TwoWay}"/>

<ListBox ItemsSource="{Binding ActiveProject.Machines}" 
SelectedItem="{Binding SelectedObject, Mode=TwoWay}"/>

This works well when I have more than one item in each list, but it fails if a list has only one item. When I select the item, SelectedObject is not updated, since the list still thinks its original item was selected. I believe this happens because the two way binding simply ignores the update from source when SelectedObject is not an object in the list, leaving the list's SelectedItem unchanged. In this way, the bindings become out of sync.

Does anybody know of a way to make sure the list boxes reset their SelectedItem when the SelectedObject is not in the list? Is there a better way to do this that doesn't suffer from this problem?

Dan's answer helped me to solve my problem too. It looks as though the key is to have bound objects rebind first to a null value and then again to the new value.

Not having Postsharp in my solution or any need to maintain a list of selected objects, this is the only code that I needed.

    Public Property MyProperty() As Object
        Get
            Return Me._MyProperty
        End Get
        Set(value As Object)
            Me._MyProperty = Nothing

            NotifyOfPropertyChange(Function() MyProperty)

            Me._MyProperty = value

            NotifyOfPropertyChange(Function() MyProperty)
        End Set
    End Property

Well, I found a way around the issue, but it makes me slightly ill. I modified the SelectedObject property in my model to this:

public Object SelectedObject
{
    get
    {
        return _selectedObject;
    }
    set
    {
        if (value != _selectedObject)
        {
            //HACK
            //Pulse 'null' between changes to reset listening list controls
            if (value != null)
                SelectedObject = null;

            if (_selectedObject != null)
                SelectedObjects.Remove(_selectedObject);

            _selectedObject = value;
            if (value != null)
                SelectedObjects.Add(value);
        }
    }
}

This forces all of the data bound list controls to reset their SelectedItem to null before we update to the 'real' SelectedObject. On a side note, the NotifyPropertyChanged stuff is being handled by PostSharp, in case you were wondering why it's missing.

I'd prefer a less hackish solution, if possible, but I do like the fact that this keeps the bindings clean in the XAML (no change required.)

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