2016-12-20 2 views
2

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

У меня есть приложение для рабочего стола wpf.

у меня есть этот COMBOBOX:

<ComboBox ItemsSource="{Binding Users, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Value.Login" 
    SelectedValue="{Binding SelectedManagerUser, 
    Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
    SelectedValuePath="Value" 
    IsSynchronizedWithCurrentItem="True" /> 

Источник данных представляет собой объект словаря:

public Dictionary<string,UserRecord> Users 
{ 
    get 
    { 
     //get data 
    } 
    set { _Users = value; RaisePropertyChanged(Constants.VM_Users); } 
} 

я добавить новую запись в моей MVVM и обновить данные.

Я тогда установить выбранный элемент в моем MVVM:

private UserRecord _selectedManagerUser; 
public UserRecord SelectedManagerUser 
{ 
    get 
    { 
     return _selectedManagerUser; 
    } 
    set 
    { 
     _selectedManagerUser = value; 
     RaisePropertyChanged("SelectedManagerUser"); 
    } 
} 
SelectedManagerUser = Users[temp]; 

public class UserRecord : ViewModelBase 
{ 
    private int _Active; 
    private int _UserRecordId; 
    private string _UserRef; 
    private string _FName; 
    private string _SName; 
    private string _Login; 
    private string _Salt; 
    private int _IsAdmin; 
    private string _FullName; 
    private string _Branch; 
    private string _Position; 
    private string _Department; 

    public int Disabled { get { return _Active; } set { _Active = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_Active); } } 
    public int UserRecordId { get { return _UserRecordId; } set { _UserRecordId = value; RaisePropertyChanged("UserRecordId"); } } 
    public string UserRef { get { return _UserRef; } set { _UserRef = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_UserRef); } } 
    public string FName { get { return _FName; } set { _FName = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_FName); } } 
    public string SName { get { return _SName; } set { _SName = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_SName); } } 
    public string Login { get { return _Login; } set { _Login = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_Login); } } 
    public string Salt { get { return _Salt; } set { _Salt = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_Salt); } } 
    public int IsAdmin { get { return _IsAdmin; } set { _IsAdmin = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_IsAdmin); } } 
    public string Branch { get { return _Branch; } set { _Branch = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_Branch); } } 
    public string Position { get { return _Position; } set { _Position = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_Position); } } 
    public string Department { get { return _Department; } set { _Department = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_Department); } } 
    public string FullName { get { return FName + ", " + SName; } set { _FullName = value; RaisePropertyChanged(InformedWorkerCommon.Constants.VM_Fullname); } } 
} 

Я знаю, что новый элемент был добавлен, потому что -

  1. Я могу видеть это ИНТ в раскрывающемся списке
  2. я поставил точку останова в моем коде и проверить.

В поле со списком отображается пустое значение.

Что-нибудь еще могу попробовать?

благодаря

+0

Что такое 'temp'? – Pikoh

+0

привет, извините, да, temp - это новый ключ, который я создал и получен из текстового поля. Опять же, ключ действителен –

+0

Я думаю, проблема в том, что ваш новый ключ/значение не находится в коллекции пользователей. Вы должны иметь в виду, что combobox не будет уведомляться о каких-либо новых элементах в коллекции Users, только когда новая коллекция будет установлена ​​в 'Users' – Pikoh

ответ

0

Ваше SelectedManagerUser свойство должно быть изменено на это. Свойство SelectedManagerUser устанавливается с новым значением, но вы не поднимаете это событие, чтобы пользовательский интерфейс не обновлялся.

private UserRecord _selectedManagerUser; 
    public UserRecord SelectedManagerUser 
    { 
     get 
     { 
      return _selectedManagerUser; 
     } 
     set 
     { 
      _selectedManagerUser = value; 
      RaisePropertyChanged("SelectedManagerUser"); 
     } 
    } 
+0

Ким, спасибо. Моя вина, что треска ei отправлена ​​для этого свойства, я просто сократил. У меня есть то, что у вас есть. Но спасибо –

+0

Если ваша версия .NET не слишком старая, 'RaisePropertyChanged (nameof (SelectedManagerUser))' также работает – Sentry

+0

@Sentry спасибо, –

0

Не уверен, что не так на вашей стороне, но может быть полезно посмотреть на рабочее решение.

XAML:

<ComboBox ItemsSource="{Binding Users}" 
      DisplayMemberPath="Value.Name" 
      SelectedValue="{Binding SelectedUser}" 
      SelectedValuePath="Value" /> 

код позади:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     Loaded += WindowLoaded; 

     var vm = new ViewModel(); 
     vm.Users.Add("u1", new UserRecord { Name = "User 1" }); 
     vm.Users.Add("u2", new UserRecord { Name = "User 2" }); 
     vm.Users.Add("u3", new UserRecord { Name = "User 3" }); 
     DataContext = vm; 
    } 

    private void WindowLoaded(object sender, RoutedEventArgs e) 
    { 
     // make sure it works after DataContext was set 
     var vm = (ViewModel)DataContext; 
     vm.SelectedUser = vm.Users["u2"]; 
    } 
} 

public class UserRecord 
{ 
    public string Name { get; set; } 
} 

public class ViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public Dictionary<string, UserRecord> Users { get; } 
     = new Dictionary<string, UserRecord>(); 

    private UserRecord selectedUser; 
    public UserRecord SelectedUser 
    { 
     get { return selectedUser; } 
     set 
     { 
      selectedUser = value; 
      PropertyChanged?.Invoke(this, 
       new PropertyChangedEventArgs(nameof(SelectedUser))); 
     } 
    } 
} 
+0

Спасибо, чтобы выскочить, но еще будет, когда вернется –

+0

привет, я вернулся. посмотрим на это сейчас. я приму свой код и вернусь к подопечным. Я должен делать что-то неправильно. –

+0

Это работало для меня, но не для тех случаев, когда UserRecord имел много разных свойств, а не только одно поле, которое у вас было. Мне удалось решить проблему, связав выбранный индекс и используя его для его выбора. –

0

Скачать Prism из Nuget и наследовать свой класс от BindableBase.

После того, как использовать это:

private UserRecord selectedManagerUser; 

public UserRecord SelectedManagerUser 
{ 
    get { return this.selectedManagerUser; } 
    set { this.SetProperty(ref this.selectedManagerUser, value); } 
} 
0

Одна из двух вещей может привести к этому. Во-первых, это может быть из-за того, что вы не устанавливаете SelectedManagerUser как экземпляр UserRecord, который НЕ находится в словаре, или что словари все еще сосут для привязки данных. Лемм накрывает их обоих.

При работе с ItemsSource и SelectedItem привязок, если вы хотите SelectedItem изменения, которые будут отражены в пользовательском интерфейсе, вы должны установить его к экземпляру, который может быть найден в ItemsSource. Элемент управления по умолчанию будет искать элемент в источнике, который по существу равен выбранному элементу. Я на 99% уверен, что он будет использовать IEquatable<T> вместо проверки ссылок, если ваши объекты реализуют его.

Если это не ваша проблема, то это потому, что словари сосать для привязки данных.

Словари являются ТЕРРИТОРИАЛЬНЫМИ для привязки данных. Просто ужас. Если вам нужна коллекция с ключом, и вы хотите привязать ее, создайте собственную коллекцию, расширяющую KeyedCollection. С некоторой дополнительной работой TItem может реализовать INPC (сделать ключ только для чтения, tho), и коллекция может реализовать INCC. Прекрасно подходит для привязки. Почему я упоминаю об этом? Читайте дальше ...

Ваша проблема является то, что в ComboBox, SelectedItem на самом деле типа KeyValuePair<string,UserRecord>, и НЕ UserRecord. Поэтому привязка НЕ ​​будет работать. Если вы возьмете копию Snoop и изучите привязки во время выполнения, вы увидите это.

Проблема в том, что элемент управления не знает, что на корточках около словарей. Все, что он знает, это IEnumerable<T>. Dictionary<K,T> реализует IEnumerable<KeyValuePair<K,T>>, поэтому элемент управления создает элемент для каждой пары значений ключа. SelectedItem также является ключевой парой значений. Таким образом, когда вы привязываете это свойство к типу UserRecord, да, он может использовать SelectedValuePath для правильного задания значения, , но он не может (не делает) [редактирование ниндзя: если это поведение не изменилось за последние несколько лет: /] перечислить перечислимую, чтобы найти правильную пару значений ключа, когда вы устанавливаете значение в вашей модели просмотра.

Если ключевое значение UserRecord является свойством внутри этого типа, то определенно создайте для него KeyedCollection. KeyedCollection<Tkey,TItem> реализует «IEnumerable», поэтому он отлично работает с привязками. Если нет, заверните его в прокси или добавьте свойство.

И когда я говорю «оберните его в прокси», кто-нибудь, кто говорит «что, как KeyValuePair?» Я собираюсь пробить вас через интернет. Прокси-сервер становится значением, с которым вы связываете. Не тратьте свое время на эту ошибку SelectedValuePath. Работайте напрямую с прокси. Когда вам нужно ваше значение, извлеките его в последний момент, а не сразу после выполнения связывания.

+0

Боюсь, я не могу согласиться с этим. Посмотрите на @Clemens ответ (у меня есть аналогичный пример сам), и привязка работает просто отлично. – Pikoh

+0

@ Pikoh Хммм, я не использовал их для нескольких релизов фреймов, поэтому они * могли * изменить поведение ItemsControl в отношении словарей. Если это так, то это может быть потому, что он неправильно обрабатывает свои ссылки. Отредактировано, чтобы включить другую возможность. Благодарю. – Will

+0

Вы должны иметь в виду, что OP не использует 'SelectedItem', а' SelectedValue' с 'SelectedValuePath = value'. Это означает, что 'SelectedManagerUser' имеет тип' UserRecord'. – Pikoh

Смежные вопросы