I'm trying to get my TwoWay-Binding to work.
These ComboBoxes should bind themselve (TwoWay) to their property in the 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");
}
}
Notice that the DataType of the ItemsSource is "CategoryLinkCollection" which Contains a "Category"-Property and an Obs.Collection of "CategoryLinkCollection". Through the SelectedValuePath the "Category" gets "saved" in the Property in the VM.
As long as I select an Item in the ComboBox everything just works fine but when I set the VM-Properties manually the ComboBoxes won't preselect the Item from the ItemsSource which contains the defined Category. Normal string values just work finde (Textboxes)
I assume it will never work because of the differen types (ComboBox = CategoryLinkCollection with ValuePath to Category, Property = Category) but maybe some of you could prove me wrong. If you need more informations let me know.
Update 1:
I just remembered that the main reason should be somewhere else because the Model "Manufacturer" got no wrapper - so the ItemsSource contains a Collection of the same data type as the property is.
XAML:
<ComboBox x:Name="_cmbManufacturer"
ItemsSource="{Binding MVM.ManufacturerCollection}"
DisplayMemberPath="Name"
SelectedItem="{Binding MVM.SelectedManufacturer, Mode=TwoWay}"/>
VM: see above.
Update 2:
At first please get away from that crappy Categorys and head over to the Manufacturer mentioned in Update 1 because it's the same issue but much easier to get in.
I now checked the SelectedManufacturer-Property after setting it manually just in case there would be some problems while setting it. The SelectedManufacturer-Property contains a Manufacturer (not null) but still the UI does not get updated.
Update 3:
I've got the following output out of the Output-Window after using the diagnostics NS:
System.Windows.Data Warning: 60 : BindingExpression (hash=43478430): Default mode resolved to TwoWay
System.Windows.Data Warning: 61 : BindingExpression (hash=43478430): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=43478430): Attach to System.Windows.Controls.ComboBox.SelectedItem (hash=10372298)
System.Windows.Data Warning: 67 : BindingExpression (hash=43478430): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=43478430): Found data context element: ComboBox (hash=10372298) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=43478430): Activate with root item Manipulation (hash=64100268)
System.Windows.Data Warning: 107 : BindingExpression (hash=43478430): At level 0 using cached accessor for Manipulation.MVM: RuntimePropertyInfo(MVM)
System.Windows.Data Warning: 104 : BindingExpression (hash=43478430): Replace item at level 0 with Manipulation (hash=64100268), using accessor RuntimePropertyInfo(MVM)
System.Windows.Data Warning: 101 : BindingExpression (hash=43478430): GetValue at level 0 from Manipulation (hash=64100268) using RuntimePropertyInfo(MVM): ManipulationViewModel (hash=11088040)
System.Windows.Data Warning: 108 : BindingExpression (hash=43478430): At level 1 - for ManipulationViewModel.SelectedManufacturer found accessor RuntimePropertyInfo(SelectedManufacturer)
System.Windows.Data Warning: 104 : BindingExpression (hash=43478430): Replace item at level 1 with ManipulationViewModel (hash=11088040), using accessor RuntimePropertyInfo(SelectedManufacturer)
System.Windows.Data Warning: 101 : BindingExpression (hash=43478430): GetValue at level 1 from ManipulationViewModel (hash=11088040) using RuntimePropertyInfo(SelectedManufacturer): Manufacturer (hash=14500136)
System.Windows.Data Warning: 80 : BindingExpression (hash=43478430): TransferValue - got raw value Manufacturer (hash=14500136)
System.Windows.Data Warning: 84 : BindingExpression (hash=43478430): TransferValue - implicit converter produced Manufacturer (hash=14500136)
System.Windows.Data Warning: 89 : BindingExpression (hash=43478430): TransferValue - using final value Manufacturer (hash=14500136)
Update 4:
Manufacturer Class:
public class Manufacturer : Base.SqlBase {
public Manufacturer(int id, string name) {
this.SqlID = id;
this.Name = name;
}
}
SqlBase Class:
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 Class:
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;
}
}
I get the SelectedItem of a GridView (Type: Entity) and hand it over to my Manipulation-View which instantiates it's ViewModel. In this ViewModel the Entity gets divided into it's parts (eg. Manufacturer) and the properties (eg. SelectedManufacturer) get set. All these steps get executed before the View gets built (before Initializecomponent). I thought in this way the View has to get the selected values when initialised - or am I wrong?
Update 5:
I really don't know why but when setting a Manufacturer when the Window is initialising the PropertyChanged-Property of the Manufacturer object is null - when I set the Manufacturer through selecting an item the Property is not null.