WPF MVVM ComboBox SelectedItem or SelectedValue no

2019-01-17 05:52发布

Update

After a bit of investigating. What seems to be the issue is that the SelectedValue/SelectedItem is occurring before the Item source is finished loading. If I sit in a break point and wait a few seconds it works as expected. Don't know how I'm going to get around this one.

End Update

I have an application using in WPF using MVVM with a ComboBox. Below is the ViewModel Example. The issue I'm having is when we leave our page and migrate back the ComboBox is not selecting the current Value that is selected.

View Model

public class MyViewModel
{
     private MyObject _selectedObject;
     private Collection<Object2> _objects;
     private IModel _model;

     public MyViewModel(IModel model)
    {
         _model = model;
         _objects = _model.GetObjects();
    }

    public Collection<MyObject> Objects
    {
         get
         {
              return _objects;
         }
         private set
         {
              _objects = value;
         }
     }

     public MyObject SelectedObject
     {
          get
          {
              return _selectedObject;
          }
          set
          {
               _selectedObject = value;
          }
      }
 }

For the sake of this example lets say MyObject has two properties (Text and Id). My XAML for the ComboBox looks like this.

XAML

<ComboBox Name="MyComboBox" Height="23"  Width="auto" 
    SelectedItem="{Binding Path=SelectedObject,Mode=TwoWay}" 
    ItemsSource="{Binding Objects}"
    DisplayMemberPath="Text"
    SelectedValuePath="Id">

No matter which way I configure this when I come back to the page and the object is reassembled the ComboBox will not select the value. The object is returning the correct object via the get in the property though.

I'm not sure if this is just an issue with the way the ComboBox and MVVM pattern works. The text box binding we are doing works correctly.

17条回答
祖国的老花朵
2楼-- · 2019-01-17 06:26

I had the same problem. The thing is. The selected item doesnt know which object it should use from the collection. So you have to say to the selected item to use the item from the collection.

public MyObject SelectedObject
 {
      get
      {
          Objects.find(x => x.id == _selectedObject.id)
          return _selectedObject;
      }
      set
      {
           _selectedObject = value;
      }
 }

I hope this helps.

查看更多
Animai°情兽
3楼-- · 2019-01-17 06:29

When leaving the current page, the CollectionView associated with the ItemsSource property of the ComboBox is purged. And because the ComboBox IsSyncronizedWithCurrent property is true by default, the SelectedItem and SelectedValue properties are reset.
This seems to be an internal data type issue in the binding. As others suggested above, if you use SelectedValue instead by binding to an int property on the viewmodel, it will work. A shortcut for you would be to override the Equals operator on MyObject so that when comparing two MyObjects, the actual Id properties are compared.

Another hint: If you do restructure your viewmodels and use SelectedValue, use it only when SelectedValuePath=Id where Id is int. If using a string key, bind to the Text property of the ComboBox instead of SelectedValue.

查看更多
Bombasti
4楼-- · 2019-01-17 06:32

I have a very simply answer for this problem. First add the following code to the View IsSynchronizedWithCurrentItem="True".

Next when ever you assign a new object in the ViewModel to that Property SelectedObject should be saved to that Property and not the private member.

The viewmodel Proptery should look like this

    public Role SelectedObject 
    {
        get { return object; }
        set
        {
            if (value != null)
            {
                if (!object.Equals(value))
                {
                    object = value;
                    OnPropertyChanged(() => SelectedObject );
                }
            }
        }
    }

This should fix the issue.

查看更多
唯我独甜
5楼-- · 2019-01-17 06:33

Have you tried implementing INotifyPropertyChanged in your viewmodel, and then raise the PropertyChanged event when the SelectedItem gets set?

If this in itself doesn't fix it, then you will be able to manually raise the PropertyChanged event yourself when navigating back to the page, and that should be enough to get WPF to redraw itself and show the correct selected item.

查看更多
Lonely孤独者°
6楼-- · 2019-01-17 06:34

I have had similar issues and it was solved by making sure I was implementing IEquatable properly. When the binding occurs, it is trying to see if the objects match so make sure you are properly implementing your equality checking.

查看更多
再贱就再见
7楼-- · 2019-01-17 06:34

I solved the problem by adding dispatcher in UserControl_Loaded event

 Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
 {
     combobox.SelectedIndex = 0;
 }));
查看更多
登录 后发表回答