I have a ComboBox whose ItemSource is bound to a list of strings (idealy i would use an Enum), this is done using the MVVM pattern.
Now i want to bind an object to the ComboBox, it's called SelectedUser and i want to bind its property: UserType, which is a string.
So i have got this:
<ComboBox ItemsSource="{Binding Path=Usertypes}" SelectedValue="{Binding Mode=TwoWay, Path=SelectedUser.UserType}" />
It works and it does change the value of the selected user if i play with it, but the problem is, that it does not display anything in the ComboBox unless i select a user, and then change the ComboBox selection, then it works, but only for that user.
I tried playing around with DisplayMemberPath, SelectedValuePath and SelectedItem,
when i added those the ComboBox did not show anything in it (there were still options to select from, but they were invisible or something).
So what should i do? Is this a bug?
I have to mention that i have got another ComboBox that has a list of ints, and it works fine.
Update:
I was informed that I'm getting this issue because the string I'm comparing to the string in the comboBox, are not actually the same.
My string comes from the Entity Framework via Ria Services. (User.UserType)
And when it compares it to the list of strings in the ComboBox ItemSource, they are not equal, for some strange reason.
And i also heard, i might have to override Equal method for that check.
but I'm not sure where and how to do so.
Is the view notified if the SelectedUser changes? I could imagine that this might be the problem; if there is no such notification the ComboBox will not reload the SelectedValue if another user is selected, it will only update the binding if you make changes yourself.
If that is not it, you also need to consider that no selected value will be displayed unless the current value exactly matches one of values in the source list.
Related
I have a WPF ComboBox which I'm using to search names. I use the MVVM pattern and it's all pretty simple:
The ComboBox Text property is bound to a "SearchString" property on the VM. The ComboBox ItemsSource is bound to a "SearchResult" property on the VM. This is a list of objects displayed using a DataTemplate. The ComboBox also triggers a "PreviewKeyDown" event and pressing enter selects the first item in the result set, with up and down arrow keys traversing the results. The SelectedItem is bound to the DataContext for a GroupBox. This part works really nicely.
When an item is selected in the ComboBox, WPF is automatically attempting to replace "Text" with my SelectedItem. This causes my results set to get emptied and "Text" to revert to an empty string.
The behaviour I'd like is that when an item is selected, the text in the ComboBox remains exactly the same, so that my user can continue to traverse the result set using up and down arrows.
Is there an elegant way to achieve this? I think that nothing will be added to the question with a code snippet, but happy to supply if wanted.
The behaviour I'd like is that when an item is selected, the text in the ComboBox remains exactly the same, so that my user can continue to traverse the result set using up and down arrows.
That's a requirement that's not built into the ComboBox control. If you want something like that, you'll have to build it yourself (and subclassing most likely won't help, you'll have to build most of a ComboBox from scratch for this).
In fact you shouldn't be binding the current item like that either, you should use the SelectedItem property, which doesn't do any conversions or copying, exactly what you want for an internal binding.
I've seen a number of suggestions for AutoComplete in WPF on a TextBox. However, they are all years old by now and many are expired without working websites.
Basically, I'm going to want to bind the TextBox to an ObservableCollection with a Model of a Person. Their Name will be displayed wen the user types as a suggestion, and will be displayed when the user selects said Person.
However I also want to be able to access the selected Persons ID as well. Is there a TextBox that is still current and can achieve what I would like it to do?
EDIT: I've attempted to use WPF TextBox AutoComplete like so:
<TextBox Text="{Binding SelectedItem.ContactMadeBy, ElementName=contactsDataGrid, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" behaviors:AutoCompleteBehavior.AutoCompleteItemsSource="{Binding EmployeeCollection}"/>
but nothing happens when I type. I've looped through EmployeeCollection and it is definitely populated, so the issue lies with the TextBox. An additional problem to this is that it needs to be bound to an IEnumerable<string> where I can't have the Persons ID as well.
I must handle SelectedValue property changing to refresh some dependent UI elements when a user selects some item in a ListBox. I use SelectedValue because I need to know a concrete value of the item, not an index in the ListBox (the index may be different under variuos circumstances) or something another. My ListBox is binded to a DataTable and SelectedValue contains ID of a row in the table.
The problem is that when I try to get SelectedValue of the ListBox within SelectionChanged event handler, I receive a prior value, not the current! So, after I spent about a hour searching for ways of solving this problem, I noted that it is relatively well-known, but solutions I've seen do not seem to be very clear. Nevertheless, I "compiled" few ideas I have encountered to the next working snippet of code:
((DataRowView)this.LISTBOXNAME.SelectedItem)["ID"]
where this is my current window and SelectedItem may be casted to DataRowView as the ListBox is binded to a DataTable as I've mentioned before. This line of code gives a proper value of the selected ListBoxItem.
But anyway, I still want to know how to make SelectedValue get proper value directly? Is it possible? Or, maybe, must I use another event (not SelectionChanged)? And if it is impossible, can somebody explain me the way of thinking of kind guys from Microsoft and why that property has such a feature?
SelectedValueChanged event works fine for getting the correct SelectedValue property, so I think the issue may be with how your listbox is setup.
You say you have it bound to a DataTable, so the items in your collection are DataRowView objects.
If you set SelectedValuePath to something like "Id", then the SelectedValue property will attempt to set the SelectedValue to DataRowView.Id, which I don't think is a valid property.
Your two alternatives here are to either
Build a collection of objects with proper properties to use for the SelectedValue
<ListBox ItemsSource="{Binding MyCollection}"
SelectedValue="{Binding SelectedId}"
SelectedValuePath="Id" ... />
where MyCollection is a collection of objects that each contain an .Id property.
Or use SelectedItem instead of SelectedValue, and work with your DataRowView objects as you are now. SelectedItem will be set to the selected item in your collection, which is of type DataRowView, so the code you have posted is how it is accessed.
((DataRowView)this.LISTBOXNAME.SelectedItem)["ID"]
Of the two, the first approach is usually preferred for WPF.
Edit: Here's an answer to your question in the comments below since it was too long to fit in a comment.
A ListBox is meant to be bound to a collection of items. When you set the ItemsSource to a DataTable, you are really binding to a collection of DataRowView objects.
There are 3 ways to get selected item from here: SelectedItem, SelectedIndex, and SelectedValue.
SelectedItem returns you the object that is selected. In this case, that's the DataRowView object, which is why you can cast it to a DataRowView.
SelectedIndex returns you the index of the selected item within the data source.
SelectedValue can only be used if you have also set the SelectedValuePath property. SelectedValuePath tells WPF which property on each data object contains the "Value" of the item, so if you set it to something like "Id", it will try to find the .Id property on each object. In your case, there is no valid property on object DataRowView that would contain your Id column data, so this doesn't work.
Hope that answers your question :)
So one particular behavior of the XAML combobox in WinRT is causing me a huge headache, because my client sees it as a defect, and doesn't care if it's the behavior of the control, he wants it changed. However, I cannot find anything that tells how to change it. The behavior I'm speaking of is that when nothing is selected the ComboBox popup opens displaying the ItemsSource in the middle of the list. I have a sorted list of countries, with the exception of US, UK, CAN being at the top. These 3 items are the most often selected items and the client wants them on top rather than having to scroll through the list to find them. That's easy enough, but because the list opens in the middle, you still have to scroll quite a bit to get to them. Is there some property I'm missing that turns this behavior off? I was able to finally convince them that the CarouselPanel wasn't a defect, but this one isn't going to fly.
Thanks in advance!
UPDATE:
So this combobox is databound through a ViewModel. in this instance, the ViewModel has no value (it is an empty string) for that particular property and so the Combobox shows empty, which is fine and desirable. When you click on the Combobox to select a value, it displays the list in the middle of the available values. this is the behavior that is undesirable. it should be showing the 1st value in the list at the top!
Well, one would think that the out of the box Combobox (there is no other built in dropdown control) would be able to work like any other combobox control in any other MS technology to date, but of course this is MS, so why should things be consistent. At any rate, I ended up having to create a "blank" entry and pre-select that item if the value in the VM is empty, and then write code in the setter of that property to ignore if "blank" item if it is selected. It's kludgy and wreaks of code smell, but it works
When you set the SelectedItem property to an object, the ComboBox attempts to make that object the currently selected one in the list. If the object is found in the list, it is displayed in the edit portion of the ComboBox and the SelectedIndex property is set to the corresponding index. If the object does not exist in the list, the SelectedIndex property is left at its current value.
I have a datagrid that is bound to a collection of my ViewModel. One of its column has values that are very specific to business requirements. On this column it can contain an alphanumeric characters.
For example I can have column values A1,A20,AA,AA12,AAA. Now I want to custom sort this values, say I want the anything with most letters should go first or etchetera. There is a default sorting with DataGrid but only do normal sorting.
My question is how would you implement this through MVVM? We can get away with this through subscribing to an event in code behind and re arrange the whole collection. However this is not what I want, I am looking for suggestions or solutions on how to approach this.
I found this link Sorting on datagrid column with binded data and converter that is attaching a property for a DataGrid but what I want to do is to attach a property to be updated every time a user click on this column. Is it possible to attach a property in a DataGrid Column?
Possible duplicate of : Sorting on datagrid column with binded data and converter but this is not using MVVM.
There are several strategies, but the most immediately accessible is to set up a DataGrid something like this...
<DataGrid ItemsSource="{Binding DriveList}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" SortMemberPath="DriveType"/>
</DataGrid.Columns>
</DataGrid>
This example shows the grid binding to a list of drives on the host machine. The first column shows the information is bound to the property 'Name'. BUT when you click the column header, it will sort on a property which is not displayed, 'DriveType'. Strange example, but it works fine.
So in your app, you would amend your collection items to include a property that is not displayed, and populate it with values according to what you want. In the example in your question, you might use something like...
MySortString = MyName.ToString().Length;
And that will cause the sort to do what you are looking for, i.e., the longest value of 'MyName' will be first with shorter values after that. You have to repopulate 'MySortString' property every time you change sort methods or reload your data source.
This strategy is MVVM compliant because all you are doing in the VM is populating an additional property. Plus you can unit test it immediatly with Nunit or whatever.
I created an attached behavior which does this in a nice MVVM-friendly way:
WPF DataGrid CustomSort for each Column
Hopefully this addresses your problem.