WPF combobox selecteditem issue
-
I had a working example of a combobox jumping to the correct selecteditem based on the choice of another combobox but I can't seem to make it work with a very simple example. I'll try to keep the code to a minimum but I don't see why a choice in "product" will not cause the correct "category" to be selected. This same code seemed to work fine when working with an EF data model based on the NW database. Main window
-
I had a working example of a combobox jumping to the correct selecteditem based on the choice of another combobox but I can't seem to make it work with a very simple example. I'll try to keep the code to a minimum but I don't see why a choice in "product" will not cause the correct "category" to be selected. This same code seemed to work fine when working with an EF data model based on the NW database. Main window
Is the product actually changing in the ViewModel? Set a breakpoint and make sure. If not, you might want to add
Mode=TwoWay,UpdateSourceTrigger=PropertyChanged
to the SelectedItem bindings. And on a related note,UpdateSourceTrigger=PropertyChanged
is completely irrelevant on aOneWay
binding, because the source never gets updated. Binding modes: *OneTime
= Only changes when the DataContext is changed *OneWay
= This property updates from the source, but changes aren't sent back *TwoWay
= Updates in both directions Unless you specifically mark the property asBindsTwoWayByDefault
, you should assume it'sOneWay
by default.Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels) -
Is the product actually changing in the ViewModel? Set a breakpoint and make sure. If not, you might want to add
Mode=TwoWay,UpdateSourceTrigger=PropertyChanged
to the SelectedItem bindings. And on a related note,UpdateSourceTrigger=PropertyChanged
is completely irrelevant on aOneWay
binding, because the source never gets updated. Binding modes: *OneTime
= Only changes when the DataContext is changed *OneWay
= This property updates from the source, but changes aren't sent back *TwoWay
= Updates in both directions Unless you specifically mark the property asBindsTwoWayByDefault
, you should assume it'sOneWay
by default.Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels)The product is changing. I added the textblocks in the 2nd and 3rd grid rows to show the values of the properties as the combobox selection is made. I also put a break in and "mySelectedCategory" is updated when a choice is made to product. I made a change to TwoWay and saw no difference. My understanding of the binding modes matches what you have listed but I thought that UpdateSourceTrigger was still needed to let the viewmodel know that an update was made from the source. With OneWay I do indeed want to say that updates are not sent back, but UpdateSourceTrigger is there to let the view know that updates were made to the model.
-
I had a working example of a combobox jumping to the correct selecteditem based on the choice of another combobox but I can't seem to make it work with a very simple example. I'll try to keep the code to a minimum but I don't see why a choice in "product" will not cause the correct "category" to be selected. This same code seemed to work fine when working with an EF data model based on the NW database. Main window
Have a look at this article Debugging WPF data bindings[^] Hopefully it can help you debug your binding. A quick tip, as
myCategory
does not override equals thenmySelectedCategory
will only be displayed/selected in the combobox ifmyCategoryList
contain the very same reference.My number one dev tool? Google
-
The product is changing. I added the textblocks in the 2nd and 3rd grid rows to show the values of the properties as the combobox selection is made. I also put a break in and "mySelectedCategory" is updated when a choice is made to product. I made a change to TwoWay and saw no difference. My understanding of the binding modes matches what you have listed but I thought that UpdateSourceTrigger was still needed to let the viewmodel know that an update was made from the source. With OneWay I do indeed want to say that updates are not sent back, but UpdateSourceTrigger is there to let the view know that updates were made to the model.
Ah, Simon nailed the problem... The category being dumped into "mySelectedCategory" isn't IN the list. It's an object created in GetMyCategory() that has the same values as one of the items in the list. So the solution is to override the Equals() function of the category, so it returns true when the ID and Name match (Or just the ID). You'll also be told to override GetHashCode (Also a good idea)... That way, the data binding system will be able to match "mySelectedCategory" to an item in the list, and select it for you.
Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels) -
Have a look at this article Debugging WPF data bindings[^] Hopefully it can help you debug your binding. A quick tip, as
myCategory
does not override equals thenmySelectedCategory
will only be displayed/selected in the combobox ifmyCategoryList
contain the very same reference.My number one dev tool? Google
In a previous version I had tried that but it appears I coded it incorrectly. For some reason I tried to implement IEqualityComparer and when I did nothing changed. Instead I tried an override to Equals and it seems to have worked. Sigh. I had the answer from a Google search a while back, I just implemented it incorrectly. Here's what I coded that appears to have worked.
Public Overrides Function Equals(obj As Object) As Boolean If IsNothing(obj) OrElse Not \[GetType\]().Equals(obj.GetType()) Then Return False End If Dim myc As myCategory = CType(obj, myCategory) Return CategoryID = myc.CategoryID End Function Public Overrides Function GetHashCode() As Integer Return CategoryID.GetHashCode ^ CategoryName.GetHashCode End Function
-
Ah, Simon nailed the problem... The category being dumped into "mySelectedCategory" isn't IN the list. It's an object created in GetMyCategory() that has the same values as one of the items in the list. So the solution is to override the Equals() function of the category, so it returns true when the ID and Name match (Or just the ID). You'll also be told to override GetHashCode (Also a good idea)... That way, the data binding system will be able to match "mySelectedCategory" to an item in the list, and select it for you.
Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels)You were correct and I posted my solution in the other post. I think I see the issue. Regarding the statement that the category wasn't "in the list", given the common example displayed here, am I missing a better way to do this? My assumption is your data layer will have functions to get a list of objects (for maybe a combobox) and also have a function to grab an object by ID. Are you implying that maybe my data layer should be doing something different for it's "get by id" type function? I'm all for learning a better method.
-
You were correct and I posted my solution in the other post. I think I see the issue. Regarding the statement that the category wasn't "in the list", given the common example displayed here, am I missing a better way to do this? My assumption is your data layer will have functions to get a list of objects (for maybe a combobox) and also have a function to grab an object by ID. Are you implying that maybe my data layer should be doing something different for it's "get by id" type function? I'm all for learning a better method.
Well the trick is that you're not returning an item from the list of categories... You're returning an entirely different item with the same properties, when you do this:
Public Function GetMyCategory(ByVal id As Int32) As myCategory
Dim results = From c In _mycateorylist
Where c.CategoryID = id
Select c
Dim rs As IEnumerable(Of myCategory) = From x In results.AsEnumerable
Select New myCategory With
{
.CategoryID = x.CategoryID,
.CategoryName = x.CategoryName
}
Return rs.FirstOrDefault
End FunctionIf you just return
results.FirstOrDefault
, it'll give you the first result from the actual list. You're also doing the same thing withGetMyCategories()
, by calling it once in the data model's constructor, and again in the view model's constructor, yielding two different collections with identical contents. The idea is to have one collection in the data model, give the view model a reference to that collection, and let the GUI bind to the view model's reference, so they all point to the same data.Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels)