2015-01-16 2 views
0

Я пытаюсь заставить свою привязку TwoWay работать.Binding ComboBox TwoWay to Property

Эти ComboBoxes должны связывать themselve (TwoWay) к их собственности в VM:

<ComboBox x:Name="_cmbCatT1" Margin="5,1,5,10" 
      ItemsSource="{Binding MVM.CategoryLinkCollection}" 
      DisplayMemberPath="Category.Name" 
      SelectedValue="{Binding MVM.SelectedTier1, Mode=TwoWay}" 
      SelectedValuePath="Category"/> 
<ComboBox x:Name="_cmbCatT2" Margin="5,1,5,10" 
      DataContext="{Binding SelectedItem, ElementName=_cmbCatT1}" 
      ItemsSource="{Binding CategoryLinkCollection}" 
      DisplayMemberPath="Category.Name" 
      SelectedValue="{Binding MVM.SelectedTier2, ElementName=_vManipulation, Mode=TwoWay}" 
      SelectedValuePath="Category"/> 
<ComboBox x:Name="_cmbCatT3" Margin="5,1,5,10" 
      DataContext="{Binding SelectedItem, ElementName=_cmbCatT2}" 
      ItemsSource="{Binding CategoryLinkCollection}" 
      DisplayMemberPath="Category.Name" 
      SelectedValue="{Binding MVM.SelectedTier3, ElementName=_vManipulation, Mode=TwoWay}" 
      SelectedValuePath="Category"/> 

VM:

private string selectedName; 
public string SelectedName { 
    get { 
     return this.selectedName; 
    } 
    set { 
     this.selectedName = value; 
     OnPropertyChanged("SelectedName"); 
    } 
} 
private string selectedDescription; 
public string SelectedDescription { 
    get { 
     return this.selectedDescription; 
    } 
    set { 
     this.selectedDescription = value; 
     OnPropertyChanged("SelectedDescription"); 
    } 
} 
private string selectedRemark; 
public string SelectedRemark { 
    get { 
     return this.selectedRemark; 
    } 
    set { 
     this.selectedRemark = value; 
     OnPropertyChanged("SelectedRemark"); 
    } 
} 
private string selectedValue; 
public string SelectedValue { 
    get { 
     return this.selectedValue; 
    } 
    set { 
     this.selectedValue = value; 
     OnPropertyChanged("SelectedValue"); 
    } 
} 
private Model.Room selectedRoom; 
public Model.Room SelectedRoom { 
    get { 
     return this.selectedRoom; 
    } 
    set { 
     this.selectedRoom = value; 
     OnPropertyChanged("SelectedRoom"); 
    } 
} 
private Model.Locker selectedLocker; 
public Model.Locker SelectedLocker { 
    get { 
     return this.selectedLocker; 
    } 
    set { 
     this.selectedLocker = value; 
     OnPropertyChanged("SelectedLocker"); 
    } 
} 
private Model.Category selectedTier1; 
public Model.Category SelectedTier1 { 
    get { 
     return this.selectedTier1; 
    } 
    set { 
     this.selectedTier1 = value; 
     OnPropertyChanged("SelectedTier1"); 
    } 
} 
private Model.Category selectedTier2; 
public Model.Category SelectedTier2 { 
    get { 
     return this.selectedTier2; 
    } 
    set { 
     this.selectedTier2 = value; 
     OnPropertyChanged("SelectedTier2"); 
    } 
} 
private Model.Category selectedTier3; 
public Model.Category SelectedTier3 { 
    get { 
     return this.selectedTier3; 
    } 
    set { 
     this.selectedTier3 = value; 
     OnPropertyChanged("SelectedTier3"); 
    } 
} 
private Model.Manufacturer selectedManufacturer; 
public Model.Manufacturer SelectedManufacturer { 
    get { 
     return this.selectedManufacturer; 
    } 
    set { 
     this.selectedManufacturer = value; 
     OnPropertyChanged("SelectedManufacturer"); 
    } 
} 

Обратите внимание, что DataType из ItemsSource является "CategoryLinkCollection", который содержит " Категория "-Property и Obs.Collection" CategoryLinkCollection ". Через SelectedValuePath «Категория» получает «сохраненную» в Свойстве в VM.

До тех пор, пока я выбираю элемент в ComboBox, все работает нормально, но , когда я устанавливаю VM-Properties вручную, ComboBoxes не будет предварительно выбирать элемент из ItemsSource, который содержит определенную категорию. Нормальные значения строки просто работают finde (текстовые поля)

Я предполагаю, что он никогда не будет работать из-за разных типов (ComboBox = CategoryLinkCollection с ValuePath для категории, Property = Category), но, возможно, некоторые из вас могут доказать, что я ошибаюсь. Если вам нужна дополнительная информация, дайте мне знать.

Update 1:

Я просто вспомнил, что главная причина должна быть где-то еще, потому что модель «Производитель» не получил обертку - так ItemsSource содержит коллекцию одного и того же типа данных, как свойство.

XAML:

<ComboBox x:Name="_cmbManufacturer" 
      ItemsSource="{Binding MVM.ManufacturerCollection}" 
      DisplayMemberPath="Name" 
      SelectedItem="{Binding MVM.SelectedManufacturer, Mode=TwoWay}"/> 

VM: смотри выше.

Update 2:

В первом пожалуйста, уйти от того, что дрянного Categorys и над головой Производителя упомянутым в Update 1, потому что это та же проблема, но гораздо проще получить в

я теперь. проверил свойство SelectedManufacturer-Property после его настройки вручную, если при его установке возникнут некоторые проблемы. SelectedManufacturer-Property содержит Производитель (но не null), но пользовательский интерфейс не обновляется.

Update 3:

У меня есть следующий выход из выходного окна после того, как с помощью диагностики NS:

System.Windows.Data Предупреждение: 60: BindingExpression (хэш = 43478430): по умолчанию режим решил TwoWay

System.Windows.Data Предупреждение: 61: BindingExpression (хэш = 43478430): по умолчанию триггер обновления решил PropertyChanged

System.Windows.Data Внимание: 62: BindingExpression (хэш = 43478430): Присоединение к System.Windows.Controls.ComboBox.SelectedItem (хэш = 10372298)

System.Windows.Предупреждение данных: 67: BindingExpression (хэш = 43478430): Разрешающая источник

System.Windows.Data Внимание: 70: BindingExpression (хэш = 43478430): Найден контекст данных элемент: ComboBox (хэш = 10372298) (КИ)

System.Windows.Data Внимание: 78: BindingExpression (хэш = 43478430): Активация с корневым элементом Манипуляцией (хэш = 64100268)

System.Windows.Data Внимание: 107: BindingExpression (хэш = 43478430): На уровне 0 с использованием кэшированного доступа для Manipulation.MVM: RuntimePropertyInfo (MVM)

System.Windows.Data Warning: 104: Binding Выражение (hash = 43478430): Заменить элемент на уровне 0 с помощью Manipulation (hash = 64100268), используя accessor RuntimePropertyInfo (MVM)

System.Windows.Data Warning: 101: BindingExpression (hash = 43478430): GetValue на уровне 0 от манипуляции (хэш = 64100268), используя RuntimePropertyInfo (MVM): ManipulationViewModel (хэш = 11088040)

System.Windows.Data Внимание: 108: BindingExpression (хэш = 43478430): на уровне 1 - для ManipulationViewModel.SelectedManufacturer найден аксессором RuntimePropertyInfo (SelectedManufacturer)

System.Windows.Data Warning: 104: BindingExpression (hash = 43478430): Заменить элемент на уровне 1 с помощью ManipulationViewModel (hash = 11088040), используя аксессор RuntimePropertyInfo (SelectedManufacturer)

System.Windows.Data Внимание: 101: BindingExpression (хэш = 43478430): ПолучитьЗначение на уровне 1 из ManipulationViewModel (хэш = 11088040), используя RuntimePropertyInfo (SelectedManufacturer): Производитель (хэш = 14500136)

System.Windows.Data Предупреждение: 80: BindingExpression (хэш = 43478430): TransferValue - есть сырое значение Производитель (хэш = 14500136)

System.Windows.Data Предупреждение: 84: BindingExpression (хэш = 43478430): TransferValue - неявный преобразователь производства Производитель (хеш = 14500136)

System.Windows.Data Внимание: 89: BindingExpression (хэш = 43478430): TransferValue - с использованием конечного значения Производитель (хэш = 14500136)

Обновление 4:

Класс Производитель:

public class Manufacturer : Base.SqlBase { 
    public Manufacturer(int id, string name) { 
     this.SqlID = id; 
     this.Name = name; 
    } 
} 

SQLBase Класс:

public abstract class SqlBase : INotifyPropertyChanged { 
    public int SqlID { get; set; } 
    private string _name; 
    public string Name { 
     get { 
      return _name; 
     } 
     protected set { 
      this._name = value; 
      PropertyChangedHandler("Name"); 
     } 
    } 

    public void SetId(int id) { 
     this.SqlID = id; 
     PropertyChangedHandler("SqlID"); 
    } 

    private void PropertyChangedHandler(string propertyName) { 
     PropertyChangedEventHandler temp = PropertyChanged; 
     if (temp != null) { 
      temp(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

Entity Класс:

public class Entity : Base.SqlBase { 

    public string Description { get; private set; } 
    public string Remark { get; private set; } 
    public int Value { get; private set; } 
    public Model.CategoryWrapper Categories { get; private set; } 
    public Model.Manufacturer Manufacturer { get; private set; } 
    public Model.Locker Locker { get; private set; } 

    public Entity(string name, string desc, string remark, int value, Model.CategoryWrapper cat, Model.Manufacturer manuf, Model.Locker locker) {   
     this.Name = name; 
     this.Description = desc; 
     this.Remark = remark; 
     this.Value = value; 
     this.Categories = cat; 
     this.Manufacturer = manuf; 
     this.Locker = locker; 
    } 

    public Entity(int id, string name, string desc, string remark, int value, Model.CategoryWrapper cat, Model.Manufacturer manuf, Model.Locker locker) { 
     this.SqlID = id; 
     this.Name = name; 
     this.Description = desc; 
     this.Remark = remark; 
     this.Value = value; 
     this.Categories = cat; 
     this.Manufacturer = manuf; 
     this.Locker = locker; 
    } 
} 

Я получаю SelectedItem из в GridView (Тип: Entity) и передать ее моей манипулированию-View, который создает экземпляр это ViewModel. В этой модели ViewModel Entity делится на части (например, Производитель), и свойства (например, SelectedManufacturer) устанавливаются. Все эти шаги выполняются до Вид создается (до Initializecomponent). Я думал, что таким образом View должен получить выбранные значения при инициализации - или я ошибаюсь?

Update 5:

Я действительно не знаю, почему, но при установке Производителя, когда окно инициализации PropertyChanged-свойстве объекта Производитель является нулевым - когда я устанавливаю Производитель через выбор пункта Свойство не равно нулю.

+0

Попробуйте использовать конвертер? Я не уверен на 100%, но поскольку вы используете пропущенные типы, это может быть проблемой. – Xeun

+0

Я только что вспомнил, что «Производитель» - это тот же тип (кроме коллекции). Я просто обновлю вопрос. – C4p741nZ

ответ

0

Похоже, я решил тайну.

Объяснение:

«Манипуляция» - вид, который должен предварительно выбрать ComboBox-значения, даваемого Entity получит свой собственный экземпляр ObservableCollection - но производитель-объект переходит в руки, что form - поэтому он не содержится в коллекции.

Решение:

Переопределение Equals-метод, чтобы проверить SQLID собственности, а не метод по умолчанию для определения равенства решить эту проблему.

0

Используйте спусковое свойство источника обновления в вашем связывании и установить его в PropertyChanged:

<ComboBox x:Name="_cmbManufacturer" ItemsSource="{Binding MVM.ManufacturerCollection}" DisplayMemberPath="Name" SelectedItem="{Binding MVM.SelectedManufacturer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
+0

Оба, установив UpdateSourceTrigger и используя тот же тип данных, не решили проблему. – C4p741nZ

0

Howsit Chill-X, Правильно ли я понимаю, что основная проблема в том, что вы хотите коробки Combo, чтобы отразить измененные выбор при обновлении модели viewModel? Если это так, вот опускающаяся версия, как вы можете это сделать.

Важные вещи, чтобы отметить (Привязка выбранного элемента к другому свойству называется SelectedCategory. При изменении SelectedCategory в VM, пользовательский интерфейс будет меняться, и если вы выбираете новый элемент в поле со списком, то SelectedCategory свойство будет обновляться

Вот вид Модель:.

public class ViewModel : INotifyPropertyChanged 
{ 
    private ObservableCollection<Category> _categoryLinkCollection; 
    public ObservableCollection<Category> CategoryLinkCollection 
    { 
     get 
     { 
      return this._categoryLinkCollection; 
     } 
     set 
     { 
      if (value != this._categoryLinkCollection) 
      { 
       this._categoryLinkCollection = value; 
       OnPropertyChanged("CategoryLinkCollection"); 
      } 
     } 
    } 

    private Category _selectedCategory; 
    public Category SelectedCategory 
    { 
     get 
     { 
      return this._selectedCategory; 
     } 
     set 
     { 
      this._selectedCategory = value; 
      OnPropertyChanged("SelectedCategory"); 
     } 
    } 
} 

Вот XAML:

<ComboBox ItemsSource="{Binding CategoryLinkCollection, Mode=TwoWay}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" /> 

Я просто использовал код за страницей, чтобы добавить фиктивные данные в коллекцию (на window_loaded и кнопку, чтобы показать, что вы можете обновить свойство VM и обновления пользовательского интерфейса.

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

     // Set the View's DataContext to our ViewModel 
     var vm = new ViewModel(); 
     this.DataContext = new ViewModel(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     // Populate Category Collection with dummy data. 
     var vm = ((ViewModel)this.DataContext); 
     vm.CategoryLinkCollection = new ObservableCollection<Category>() 
     { 
      new Category("Cat 1"), 
      new Category("Cat 2"), 
      new Category("Cat 3"), 
      new Category("Cat 4"), 
      new Category("Cat 5"), 
      new Category("Cat 6"), 
     }; 
     vm.SelectedCategory = vm.CategoryLinkCollection[0]; 
    } 

    private void btn_Click(object sender, RoutedEventArgs e) 
    { 
     var vm = ((ViewModel)this.DataContext); 
     vm.SelectedCategory = vm.CategoryLinkCollection[3]; 
    } 
} 

Теперь у вас есть ComboBox, который обновляется с VM и UI.

+0

Единственное различие, которое я вижу, это дополнительный режим в «ItemsSource», или я ошибаюсь? Давайте уберемся от этой категории, потому что они немного сложнее, чем кажется. Давайте возьмем производителя, которого я упомянул в своем обновлении. Когда я выбираю нового производителя через ComboBox, все работает отлично - OneWay = checked. Но когда я меняю свойство SelectedManufacturer-Property вручную на другого производителя, пользовательский интерфейс не обновляется (ComboBox пуст).(Выбранный изготовитель - это элемент, который содержится в собрании изготовителя, просто для того, чтобы упомянуть его). – C4p741nZ

+0

Производитель ComboBox выглядит правильно. Я хотел бы проверить следующее: 1) Поместите контрольную точку на набор SelectedManufacturer-Property. Когда вы обновляете ComBox через пользовательский интерфейс, удаляется ли точка останова? 2) Когда вы установили свойство SelectedManufacturer-Property из кода, стоящего за/VM, вызывает ли он _OnPropertyChanged_ с правильно названным именем свойства? 3) Является ли ваш ManufacturerCollection _ObservableCollection_? 4) Если все вышеописанное правильно, я бы поставил точку останова в методе _OnPropertyChanged_ и посмотрел, действительно ли вызывает вызовы _PropertyChanged_. –

+0

I # ve установить brakepoint на множестве - Idk, почему, но свойство "PropertyChanged" равно null ... – C4p741nZ

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