I've got a simple WPF ComboBox, displaying Orders/Positions on the Financial Markets.
<ComboBox Name="TradeDropDown"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
ItemsSource="{Binding Path=ActiveOrders}"
DisplayMemberPath="OrderLabel"
SelectedItem="{Binding Path=SelectedOrder, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True" />
I need to see at a glance how many items are in the list. I've added a TextBlock above with summary information.
I don't like it, and would prefer to have the items in the dropdown listed like:
(1/2) Working Short 425K
(2/2) Filled Long 979K
etc - and have the 1/2 numbers correctly update as items are added and removed from the list.
The Items are stored in a BindingList.
Is there an easy way to do this?
Is there an easy way to do this?
Add another property to the class where the OrderLabel property is defined that returns a string like "(1/2) Working Short 425K" and set the DisplayMemberPath property of the ComboBox to the name of this property.
Make sure that the class implements the INotifyPropertyChanged interface.
You then set the new property to a new value and raise the PropertyChanged event whenever you want to update the label in the ComboBox.
Related
Imagine your working on a UI for an Wedding Planner app. You'll have a list of guests and you want to display their name on the screen next to a combobox containing values of 'Will Attend' / 'Maybe' / 'No'.
I've tried to something just that....I have a collection of items inside a view model (the guests). For each of those items I want to display a Label and a ComboBox. Each ComboBox has the same values in the drop down (the possible responses).
I've created an ItemTemplate that contains a label and a combobox. I bind it to my collection of guests and it works as expected. I'm using ancestor binding so that the ComboBox's ItemsSource is bound to the list of possible responses. That works great.
What I'm struggling with is how to bind the SelectedItem to get the values the user selects? I want to have a collection of selected values on the ViewModel somehow, but I'm having a lot of trouble finding the correct words to describe this / search for it.
Can anyone help me? Am I going about this the wrong way?
You may create an enum for the attendance state and add an Attendance property to your Guest class:
public enum Attendance
{
Yes,
No,
Maybe
}
public class Guest
{
...
public Attendance Attendance { get; set; } // raise PropertyChanged event if necessary
}
Now you could set the Tag property of the ComboBox items to the appropriate enum value and bind the SelectedValue property:
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox SelectedValue="{Binding Attendance}" SelectedValuePath="Tag">
<TextBlock Tag="Yes">Will Attend</TextBlock>
<TextBlock Tag="No">Won't Attend</TextBlock>
<TextBlock Tag="Maybe">May Attend</TextBlock>
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
I am having a furious struggle with the WPF Combobox in our bi-languge application.
I have the combobox binded to a collection. I have a button that replaces the values of the collection with their corresponding string values in another language.
What is the problem: I select a value from the drop down list. I change the language, by pressing a button, then the displayed value remains on the old language, but when the drop down is dropped the values in in are replaced with the right ones.
Here is my XAML:
<ComboBox x:Name="ProjectClassComboBox"
Width="150"
ItemsSource="{Binding Path=ProjectClassCollection}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
SelectedValue="{Binding Path=RegionContext.CurrentItem.ClassNomenclatureId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Update: Because it is asked in the comments I must add that
the collectionis a custom class of ours, DERIVED from ObservableCollection, that is fairly complex. The collection items must be implementing INotifyPropertyChanged, and the collection has a listener to the PropertyChanged event of each item.
It just looks like the displayed text of the combo is not updated, when the drop down list and the selected item value is updated.
Binding ObservableCollection (and derrived class too) works only in case where you add or delete items, cause that's the action that invokes change event. If you need to manipulate data inside collection I suggest using BindingList. Maybe some kind of wrapper would be solution for you.
Do one thing. In the button click,
1. get the selected index in the combo box
2. Replace all the strings in the collection
3. set the selecteditem property of the combobox using the selected index that we have stored earlier in the step 1.
So, it's a bit late but we just encountered the same problem on a project that needs to support multiple languages.
Our solution was to return a new instance of ObservableCollection on the property getter.
So, your code should look like this:
<ComboBox x:Name="ProjectClassComboBox"
ItemsSource="{Binding Path=ProjectClassCollection}"/>
And in your ViewModel:
public ObservableCollection<Project> ProjectClassCollection
{
get {return new ObservableCollection<Project>(){_projectClassCollection};}
set {...}
}
This code is a quick snippet from my memory. It will not work if you just copy-pasta, but the idea is that another collection instance worked for us.
We tried to call OnPropertyChanged(nameof(ProjectClassCollection)) but that didn't work. We tried to set UpdateSourceTrigger=PropertyChanged in XAML but that didn't work either. Having a new instance worked.
Hope this helps and saves you time, cheers!
The Problem:
Combobox shows no selected item on startup. To be exact: Item and Value are null, index is -1 and valuepath is empty. While the functionality of the binding itself seems to work, it simply refuses to show a value on startup.
What I am trying to do:
I have two lists of objects. ListOne is the full list of all available objects.
ListTwo is a list of 21 "selected" objects out of the objects in list one.
So I want to bind ListOne to a combobox with the namevalue of the object to show. Meanwhile, the selected object should be bound to ListTwo[index].
Basically, if I change the selection in the combobox I want ListTwo[index] to be a copy of the now selected object.
What I have right now:
The Object in question:
public class Rezept
{
public string strName { set; get; }
public string strSomething { set; get; }
}
The XAML-Code:
<ComboBox x:Name="comboboxName" ItemsSource="{Binding listOne}" SelectedValue="{Binding listTwo[0], Mode=TwoWay}" DisplayMemberPath="strName"/>
This seems to be working, as in selecting something updates ListTwo just fine. But on startup the combobox has nothing selected.
Another XAML-Code try:
<ComboBox x:Name="comboboxName" ItemsSource="{Binding listOne}" SelectedItem="{Binding listTwo[0], Mode=TwoWay}" DisplayMemberPath="strName"/>
This seems to behave exactly as the first, even tho it sounds more "correct".
Try three on the XAML:
<ComboBox x:Name="comboboxName" ItemsSource="{Binding listOne}" SelectedItem="{Binding listTwo[0], Mode=TwoWay}" DisplayMemberPath="strName" SelectedValue="{Binding listTwo[0].strName}"/>
This changes nothing. Neither does binding to SelectedValuePath it seems.
What do i have to change so the combobox actually shows ListTwo[0] on startup? I did make sure ListTwo[0] actually has the right value. It does get populated by a xml file on startup tho, after the UI is loaded. Would this be a case of needing a "OnPropertyChanged"-Event somewhere? And if so, where? I am out of ideas otherwise.
Could still use a hand here tho :-(
Instead of binding with SelectedValue property, you should have bind it with SelectedItem property like as follows:
<ComboBox x:Name="comboboxName" ItemsSource="{Binding listOne}" SelectedItem="{Binding listTwo[0], Mode=TwoWay}" DisplayMemberPath="strName"/>
So, since noone seems to have a solution (including myself after another 5 days of searching) I will at least post my VERY dirty workaround.
I made a List where I added every combobox in question via a loop (21 ones). Then I did another loop and manually set the Index of listOne in every Combobox to match the right value in listTwo. So it simply checks which index contains the right name and set it to that like this:
for(int i = 0, i < 21, i++)
{
listCombo[i].SelectedIndex = listOne.IndexOf(listOne.Where(x => x.name == listTwo[i].name).First();
}
This only has to be called once one on startup of the programm, since listTwo actually has the right values in the right order (as seen in the XML save file as well).
Id still much rather find out how this is supposed to work in XAML Databinding tho. So if anyone has a real answer later on, feel free to poke me so i can update this one.
This question deals with a dinky little Winforms GUI. Let it be known that I have basic knowledge of data bindings and INotifyPropertyChanged and use both in my ViewModels in WPF. But I don't know Winforms. This is for a school assignment.
So I have a class that has a DisplayName property. I also have a ListBox whose Items are a sequence of instances of my class. I have pointed myListBox.DisplayMember = "DisplayName"; After changing a value in an instance of my class that will cause the DisplayName property to return a different value, how do I tell my ListBox to pull the DisplayName property again to refresh its value?
I needed to do the same thing but with a combobox. The workaround I found is to clear and reset the DisplayMember property.
This worked:
myComboBox.DisplayMember = null;
myComboBox.DisplayMember = "DisplayName";
It's important to note that this is perhaps not the best solution as it will cause multiple SelectedValueChanged events but the end result is successful.
Doing it this way probably requires re-binding the listbox, loosing selectedIndex etc.
One workaround is to forget about the DisplayMember property and handle the Format event of the ListBox instead. Something like (from memory) :
// untested
e.Value = (e.Item as MyClass).DisplayValue;
I know this was ages ago but I had similar problem and could not find satisfying solution and finally solved with this single line at the end after updating the values:
bindingsource.EndEdit();
Items on listbox reflects any changes entered into textboxes after Update button clicked. So after lines like this:
textbox1.DataBindings["Text"].WriteValue();
textbox2.DataBindings["Text"].WriteValue();
just insert this line:
bindingsourcevariable.EndEdit();
Hope this helps others who also encounter similar problem but haven't found the right solution
Here is solution code that does everything in XAML as opposed to back end C#. This is how I do my projects utilizing MVVM (minimizing the back end code, and if possible having no back end code)
<ListBox x:Name="lstServers" HorizontalAlignment="Left" Height="285" Margin="20,37,0,0" VerticalAlignment="Top" Width="215"
ItemsSource="{Binding Settings.Servers}"
SelectedItem="{Binding Settings.ManageSelectedServer, Mode=TwoWay}"
DisplayMemberPath="UserFriendlyName"/>
This is a listbox on the Window. The keys to point out here, which can be very tricky, are the usual ItemsSource property being set to a Settings object on my view model, which has a Servers Observable collection.
Servers is a class that has a property called UserFriendlyName.
public sealed class AutoSyncServer : ObservableModel
{
public AutoSyncServer()
{
Port = "80";
UserFriendlyName = "AutoSync Server";
Server = "localhost";
}
private string _userFriendlyName;
public string UserFriendlyName
{
get { return _userFriendlyName;}
set
{
_userFriendlyName = value;
OnPropertyChanged("UserFriendlyName");
}
}
This is a partial code snippet for you of the class itself.
The SelectedItem of the ListBox is bound to an instance of the Selected object that I store in the model view called ManageSelectedServer.
The tricky part here is the DisplayMemberPath is set to "UserFriendlyName" as opposed to "{Binding UserFriendlyName}". This is key
If you use {Binding UserFriendlyName} it will display the UserFriendlyNames in the collection but will not reflect any changes to that property.
The XAML for the TextBox where the user can update the user friendly name (which should change the text in the listbox also) is:
<TextBox x:Name="txtDisplayName" HorizontalAlignment="Left" Height="23" Margin="395,40,0,0" TextWrapping="Wrap"
Text="{Binding ElementName=lstServers,Path=SelectedItem.UserFriendlyName, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Top" Width="240"/>
This sets the Text property of the TextBox and binds it to the ListBox element lstServers SelectedItem property UserFriendlyName. I've also included an UpdateSourceTrigger=PropertyChanged so that any changes made to the text source notify that they have been changed.
XAML is tricky!
I have a combo box which is populated on selection's from two other combo'.
No problem I have this working.
Problem is I only want to activate the Selected Item binding after this has happened.
Here is my combo
<cuc:ComboBox Name="GopLenTypeCombo" Width="240" Height="24"
IsSynchronizedWithCurrentItem="True"
SelectedValue="{Binding Mode=TwoWay, Source={StaticResource ProfileDataProvider}, XPath=GopLenType}"
IsEnabled="False"/>
How do I stop the SelectedValue binding working untill I have populated the combo ?
I don't know whether this is possible in pure XAML, but if you have an underlying ViewModel, this wouldn't be too hard:
What you would need to do is to bind your third ComboBox to a property on the ViewModel (let's call this property Combo3Items).
You would also need to bind the two first ComboBoxes to properties on the same ViewModel (let's call these Combo1Items and Combo2Items, respectively). In addition to that, you could bind both of these ComboBoxes' SelectedValue to properties on the ViewModel, so that the ViewModel knows which items are selected.
Initially, Combo3Items would be empty, but as soon as the two bound SelectedValues are properly assigned, you can fill Combo3Items and raise an INotifyPropertyChanged event.
The MVVM architecture is very powerful. If you don't already know it, you can read more about it here.