WPF MVVM ComboBox SelectedItem или SelectedValue не работает - PullRequest
40 голосов
/ 19 марта 2009

Обновление

После небольшого расследования. Проблема, по-видимому, заключается в том, что SelectedValue / SelectedItem происходит до завершения загрузки элемента Item. Если я сижу в точке останова и жду несколько секунд, она работает как положено. Не знаю, как я собираюсь обойти это.

Окончание обновления

У меня есть приложение, использующее в WPF MVVM с ComboBox. Ниже приведен пример ViewModel. У меня проблема в том, что когда мы покидаем нашу страницу и возвращаемся назад, ComboBox не выбирает выбранное текущее значение.

Просмотр модели

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

Для примера расскажем, что MyObject имеет два свойства (Text и Id). Мой XAML для ComboBox выглядит следующим образом.

1020 * XAML *

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

Независимо от того, каким образом я настраиваю это, когда я возвращаюсь на страницу и объект повторно собирается, ComboBox не будет выбирать значение. Объект возвращает правильный объект через свойство get в свойстве.

Я не уверен, является ли это просто проблемой способа работы шаблонов ComboBox и MVVM. Привязка текстового поля, которую мы делаем, работает правильно.

Ответы [ 17 ]

29 голосов
/ 26 июня 2012

Настройка IsSynchronizedWithCurrentItem="True" у меня сработала!

27 голосов
/ 19 марта 2009

Вы пытались реализовать INotifyPropertyChanged в своей модели представления, а затем вызвать событие PropertyChanged, когда SelectedItem установлено?

Если это само по себе не исправляет ситуацию, вы сможете вручную вызвать событие PropertyChanged при переходе обратно на страницу, и этого должно быть достаточно, чтобы WPF перерисовал себя и отобразил правильный выбранный пункт.

21 голосов
/ 13 января 2011

Вам необходимо поместить свойство ItemsSource ДО свойства SelectedItem. Несколько дней назад я наткнулся на блог, в котором упоминается проблема.

11 голосов
/ 20 марта 2009

У меня были похожие проблемы, и это было решено путем проверки правильности реализации IEquatable . Когда связывание происходит, оно пытается определить, совпадают ли объекты, поэтому убедитесь, что вы правильно реализуете проверку на равенство.

10 голосов
/ 03 октября 2012

В этом случае привязка выбранного элемента не работает, поскольку хэш-идентификаторы объектов различаются.

Одно из возможных решений:

На основе идентификатора выбранного элемента восстановите объект в коллекции источников и установите для него свойство выбранного элемента.

Пример:

<ctrls:ComboBoxControlBase SelectedItem="{Binding Path=SelectedProfile, Mode=TwoWay}" ItemsSource="{Binding Path=Profiles, Mode=OneWay}" IsEditable="False" DisplayMemberPath="Name" />

Свойство, привязанное к ItemSource:

public ObservableCollection<Profile> Profiles
{
   get { return this.profiles; }
   private set { profiles = value; RaisePropertyChanged("Profiles"); }
}

Свойство, привязанное к SelectedItem:

public Profile SelectedProfile 
{
    get { return selectedProfile; }
    set
    {
        if (this.SelectedUser != null)
        {
            this.SelectedUser.Profile = value; 
            RaisePropertyChanged("SelectedProfile");  
        } 
    } 
}

Код восстановления:

    [Command("SelectionChanged")]
    public void SelectionChanged(User selectedUser)
    {
        if (selectedUser != null)
        {
            if (selectedUser is User)
            {
                if (selectedUser.Profile != null)
                {
                    this.SelectedUser = selectedUser;
                    this.selectedProfile = this.Profiles.Where(p => p.Id == this.SelectedUser.Profile.Id).FirstOrDefault();
                    MessageBroker.Instance.NotifyColleagues("ShowItemDetails"); 
                }
            }
        }            
    }

Надеюсь, это поможет вам. Я потратил много времени на поиск ответов, но не смог найти.

4 голосов
/ 17 февраля 2011

При выходе из текущей страницы CollectionView, связанный со свойством ItemsSource ComboBox, удаляется. А поскольку свойство ComboBox IsSyncronizedWithCurrent по умолчанию имеет значение true, свойства SelectedItem и SelectedValue сбрасываются.
Это кажется внутренней проблемой типа данных в привязке. Как уже предлагалось выше, если вы используете SelectedValue вместо привязки к свойству int в viewmodel, это будет работать. Для вас ярлыком было бы переопределить оператор Equals в MyObject, чтобы при сравнении двух объектов MyObject сравнивались фактические свойства Id.

Еще один совет: если вы реструктурируете свои модели представления и используете SelectedValue, используйте его только тогда, когда SelectedValuePath=Id, где Id равно int. Если используется строковый ключ, привязайте к свойству Text ComboBox вместо SelectedValue.

3 голосов
/ 21 марта 2009

Я уже заметил это поведение. Я заметил, что свойство SelectedIndex не вызывает ту же ошибку. Если вы можете реструктурировать вашу ViewModel, чтобы выставить индекс выбранного элемента и привязать к нему, вы должны быть готовы.

2 голосов
/ 04 августа 2011

У меня очень простой ответ на эту проблему. Сначала добавьте следующий код в View IsSynchronizedWithCurrentItem = "True".

Далее, когда бы вы ни назначали новый объект в ViewModel для этого свойства, SelectedObject должен сохраняться в этом свойстве, а не в частном члене.

Проптеры модели представления должны выглядеть следующим образом

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

Это должно решить проблему.

2 голосов
/ 14 мая 2010

У меня была такая же проблема. Дело в том. Выбранный элемент не знает, какой объект он должен использовать из коллекции. Поэтому вы должны сказать выбранному предмету, чтобы использовать предмет из коллекции.

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

Надеюсь, это поможет.

1 голос
/ 09 февраля 2011

Я боролся с этой проблемой некоторое время. В моем случае я использовал комплексный тип (Список) в качестве источника элемента и использовал KeyType в качестве выбранного значения. В событии load для KeyType было установлено значение null. Это заставило все сломаться. Ни один из подэлементов не будет обновлен при изменении ключа. Оказалось, что когда я добавил проверку, чтобы убедиться, что предлагаемое значение для KeyType не равно нулю, все работало как ожидалось.

    #region Property: SelectedKey
    // s.Append(string.Format("SelectedKey : {0} " + Environment.NewLine, SelectedKey.ToString()));

    private KeyType _SelectedKey = new KeyType();
    public KeyType SelectedKey
    {
        get { return _SelectedKey; }
        set
        {
            if(value != null )
                if (!_SelectedKey.Equals(value))
                {
                    _SelectedKey = value;
                    OnPropertyChanged("SelectedKey");
                }
        }
    }
    #endregion SelectedKey
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...