Displaying cultures in combo box and selecting - wpf

I'm trying to display cultures in the combox box and I want the user to receive the DisplayName of the culture when selected but I get culture code ie 'en', 'ar' etc
The itemsource of the combo box is
ItemsSource="{Binding Path=SupportedCultures, Mode=OneWay}" SelectedItem="{Binding SelectedItem.Language}" SelectedValue="DisplayName" DisplayMemberPath="DisplayName"
SupportedCultures property
public static List<CultureInfo> SupportedCultures
{
get
{
return _SupportedCultures;
}
}
How can I get DisplayName in my selectedItem's Language property which is of type string?

SelectedItem requires the same kind of object that your ItemsSource is bound to, so don't use that. If you want to select by the value of a property, then use SelectedValue, and to tell WPF which property to check for that value, use SelectedValuePath:
ItemsSource="{Binding SupportedCultures, Mode=OneWay}"
SelectedValue="{Binding SelectedItem.Language}"
SelectedValuePath="DisplayName"
DisplayMemberPath="DisplayName"

Your code is almost correct. Your List is static. So, to bind to it, you should use {x:Static} source:
ItemsSource="{Binding Source={x:Static yournamespace:YourClassName}, Path=SupportedCultures, Mode=OneWay}"
DisplayMemberPath="DisplayName"
Note that SelectedItem="{Binding SelectedItem.Language}" binds your selected CultureInfo to your ComboBox's DataContext. So, in this case a DataContext of your ComboBox should have object SelectedItem with CultureInfo Language {get;set;} property. I don't think that's what you are looking for?)

Related

Binding TwoWay to SelectedItem: "Wrong way" synchronization on initialization

I am trying to bind a property of my DataContext to the SelectedItem on a ComboBox like this:
<ComboBox x:Name="ElementSelector"
ItemsSource="{Binding Source={StaticResource Elements}}"
DisplayMemberPath="ElementName"
SelectedItem="{Binding ValueElement, Mode=TwoWay}">
where the Elements resource is a CollectionViewSource (don't know, whether this matters).
When everything is initialized, the property ValueElement of the DataContext is set to the first item in the CollectionViewSource. What I want, is to initialize it the other way around: I would like to set SelectedItem of the ComboBox to the value of the property or null if no matching item is contained.
How can this be done?
EDIT - Additional information:
The ComboBox is part of a DataTemplate:
<DataTemplate x:Key="ReferenceTemplate"
DataType="viewModels:ElementMetaReferenceViewModel">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<ResourceDictionary>
<views:ElementsForReferenceViewSource x:Key="Elements"
Source="{Binding DataContext.CurrentProject.Elements, ElementName=Root}"
ReferenceToFilterFor="{Binding}"/>
</ResourceDictionary>
</StackPanel.Resources>
<TextBlock Text="{Binding PropertyName}"/>
<ComboBox x:Name="ElementSelector"
ItemsSource="{Binding Source={StaticResource Elements}}"
DisplayMemberPath="ElementName"
SelectedItem=""{Binding ValueElement, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
The ElementsForReferenceViewSource simply derives from CollectionViewSource and implements an additional DependencyProperty which is used for filtering.
The DataContext of the items in the CollectionViewSource look like this:
public class ElementMetaReferenceViewModel : ViewModelBase<ElementMetaReference, ElementMetaReferenceContext>
{
...
private ElementMetaViewModel _valueElement;
public ElementMetaViewModel ValueElement
{
get { return _valueElement; }
set
{
if (value == null) return;
_valueElement = value;
Model.TargetElement = value.Model;
}
}
...
}
For people encountering the same issue
The above code works as expected. The solution was getting the stuff behind the scenes right. Make sure, that the instance of the ViewModel which is the value of the property you want to bind to is definitely contained in the CollectionViewSource.
In my case the issue was deserializing an object tree incorrectly, so objects were instantiated twice. Then for each object a distinct ViewModel was initialized and then obviously the value of the property was not contained in the list.
Remark
To check whether this is an issue in your case, you can try the following:
Override the ToString() methods of the ViewModels displayed in the ComboBox like this:
public override string ToString()
{
return "VM"+ Model.GetHashCode().ToString();
}
Then you can easily compare the items in the source collection with the value on your property. Not the most professional way, but it did the job for me.

wpf binding combobox selectedvaluepath

I have a list of type string(selectedextensionvalue) in my viewmodel. How can I bind selectedvaluepath(which is also of type list string) of my combobox to selectedextensionvalue. I don't know the syntax. May anyone help?
Thanks in advance,
Bilge
If you have a collection of strings, so you do not need to use SelectedValuePath property. You can add some string field to your ViewModel of string type.
public string SelectedStringValue
{
get;
set;
}
and in xaml:
<ComboBox ItemsSource="{Binding Path=selectedextensionvalue}"
SelectedItem="{Binding Path=SelectedStringValue, Mode=OneWayToSource}" />
EDIT:
But, if you want ComboBox to select some special item (for example, which you store in the database), so property SelectedStringValue should to raise PropertyChanged notification in setter, and the xaml will be the following:
<ComboBox ItemsSource="{Binding Path=selectedextensionvalue}"
SelectedItem="{Binding Path=SelectedStringValue, Mode=TwoWay}" />

Binding ComboBox Text property using a converter

I'm having troubles using a WPF ComboBox in the following scenario:
ViewModel
Provides a ObservableCollection<T>; This collection contains a list of items the user may select.
Provides a property of type T representing the selected item.
The user shall be able to select either an existing item from the items in the ObservableCollection<T> or add a new item by typing in the string representation.
I have a converter available able to convert a item of type T to string and vice versa.
View
My ComboBox bound to the collection and the selected item properties:
<ComboBox ItemsSource="{Binding Path=MyObservableCollection}"
SelectedItem="{Binding Path=MySelectedItem}"
IsReadOnly="False" IsEditable="True"/>
The data template used to display the items correctly:
<DataTemplate DataType="{x:Type T}">
<TextBlock Text="{Binding Converter={StaticResource ResourceKey=MyConverter}}"/>
</DataTemplate>
The Problem
Items in the drop down list of the ComboBox are displayed correctly using the convert. The selected item displayed in the TextBox of the ComboBox is not displayed correctly; Instead of using my converter, the ToString method is used.
Is it possible to specify a converter for the Text property? I tried using the following code:
<ComboBox ItemsSource="{Binding Path=MyObservableCollection}"
SelectedItem="{Binding Path=MySelectedItem}"
Text="{Binding Path=MySelectedItem, Converter={StaticResource ResourceKey=MyConverter}}"
IsReadOnly="False" IsEditable="True"/>
This solves the display problem but now I get the Type.FullName of T in the converters ConvertBack method - which can of course not be converted.
Summary
I want the user to be able to select an item from a collection, allowing him to add new items by entering the string representation. The items in the collection shall be converted between string and object representation using a converter. The conversion shall be done in both the drop down list and the text box of the ComboBox.
Edit
Here is the code in my converter - no magic there just straightforward conversion:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return MyConverter.Convert(value as T);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return MyConverter.Convert(value as string);
}
public static string Convert(T key)
{
// Conversion from T to string.
}
public static T Convert(string key)
{
// Conversion from string to T.
}
}
Ok, now I found something that does what I want:
<TextBox Text="{Binding Path=MySelectedItem, Converter={StaticResource ResourceKey=MyConverter}}"/>
<ListBox ItemsSource="{Binding Path=MyObservableCollection}"
SelectedItem="{Binding Path=MySelectedItem, Converter={StaticResource ResourceKey=MyConverter}}"/>
This does exactly what I want; I can select predefined values and the user may add values on his own. Is it possible to do this with a ComboBox?
In case someone facing same issue and don't want to cope with having a string property to bound to.
You can use the following
<ComboBox
ItemsSource="{Binding Path=MyObservableCollection}"
Text="{Binding MySelectedItem, Converter={StaticResource DisplayConverter}}"
SelectedValue="{Binding MySelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource DisplayConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
Notice the binding is done on the SelectedValue, not SelectedItem.
Then the display converter is added both to the Text & Itemtemplate properties.
On the Text property it will be used to convert the selected item display value.
On the ItemTemplate, to convert display values within the list box
I even use this snippet with Enum collection coming from ObjectDataProvider defined in the xaml. My enums have DisplayString attribute and combobox behave just fine to display the string value representation of the enums.
HTH
I now use a different approach for the problem:
My view model provides a observable collection and a string property. The collection is bound to the ItemsSource property of the ComboBox, the selected item to the string property.
<ComboBox
ItemsSource="{Binding Path=MyCollection}"
Text="{Binding Path=MyProperty, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
IsReadOnly="False" IsEditable="True"/>
UpdateSourceTrigger=LostFocus part is used to prevent unnecessary updates.

DisplayMemberPath property of combo box not working as expected with source being a dictionary with custom key

I am having a ComboBox in wpf which is having its source as a IDictionary<Key, String> where 'Key' is the custom key. The ComboBox is defined as follows:
<ComboBox
x:Name="MD_PDIR_COMBO_SOURCE"
Grid.Row="0"
Style="{DynamicResource USButtonComboBoxStyle}"
Margin="14,5"
VerticalAlignment="Top"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Path=SourcesComboList}"
DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding Path=SelectedSource}"
SelectionChanged="MD_PDIR_COMBO_SOURCE_SelectionChanged"
/>
Now the issue I am facing is, although DisplayMemberPath is set to the "Value" of the dictionary which is a String, the Visual text being displayed in the combo box on selecting an item is BLANK/EMPTY.
Although all the desired functions on combo box selection change are happening correctly but the values/text is not shown after we select an item.
Kindly help!
Does your style set the ItemTemplate at all?
Setting DisplayMemberPath is a shortcut way of saying the ItemTemplate should be a TextBlock with it's Text bound to whatever is in DisplayMemberPath, so setting the ItemTemplate in addition to DispalyMemberPath will override it and make DisplayMemberPath useless
This work OK
public string Value{ get; set; }
This doesen't work !
public string Value;
Conclusion: DisplayMemberPath indicates a property of your item object not a field. Use getter and setter: { get; set; }
i assume that you have a dictionary like this?
SourcesComboList = Dictionary<string,string>();
if you just wanna check wether your Displaymemberpath works alter your combobox to this
<ComboBox Grid.Row="0"
ItemsSource="{Binding Path=SourcesComboList}"
DisplayMemberPath="Value"
SelectedValuePath="Key">
</ComboBox>
if this is working the problem is not DisplayMemberPath :)
I had the similar problem with internal property.
The DisplayMemberPath is working only for public properties.
I guess the issue with the original question might be ComboBox does not query the Dictionary to know its Item Type instead it looks at the individual Dictionary Item (not the Value) which does not have any Key and Value properties.

WPF Combobox is changing source via SelectedValue when ItemsSource is loaded

I have this combobox in my WPF window.
<ComboBox DisplayMemberPath="Description" SelectedValuePath="ID" ItemsSource="{Binding Source={StaticResource CvsPrinters}}" SelectedValue="{Binding CheckPrinterID}" />
My problem is that when loading the window, the SelectedValue binding is causing my source data to change to the first item in the ItemsSource, instead of setting the Combobox's SelectedValue to the appropriate item in the ItemsSource.
The CheckPrinterID is from a listview selection datacontext, and this problem only occurs to the item initially selected in that listview on load. When I select another item in the listbox, the combobox correctly selects the proper item and all is fine, but unfortunately my initial item has been updated and is now incorrect.
I guess you are trying to synchronize ListView and ComboBox through a common property. Try setting IsSynchronizedWithCurrentItem to True in ListView and make sure SelectedItem or SelectedIndex for ListView is set during load.
Try re-arranging ItemsSource before DisplayMemberPath.
If you have some flexibility in the DataContext object you could try changing the selected CheckPrinter property to be of the data object type instead of the ID and switch to using SelectedItem instead of SelectedValue (for some reason SelectedValue behaves differently, especially at initial load) and then extract the ID from that value in code.
If you can't use the CheckPrinter objects in your DataContext object for whatever reason, you could also go the opposite direction on the UI side by using a list of IDs as the ItemsSource, and again using SelectedItem. To get the list to show what you want in the ComboBoxItems you would then need to use an IValueConverter to pull out Description values based on IDs:
<ComboBox ItemsSource="{Binding Source={StaticResource CvsPrinterIds}}" SelectedItem="{Binding CheckPrinterID}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock >
<TextBlock.Text>
<Binding>
<Binding.Converter>
<local:MyDescriptionLookupConverter Printers="{StaticResource CvsPrinters}"/>
</Binding.Converter>
</Binding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
and a simple converter to do the ID-Description lookup (add some null and cast checks):
public class MyDescriptionLookupConverter : IValueConverter
{
public IEnumerable<Printer> Printers { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Printers.First(p => p.Id == (int)value).Description;
}
...
}

Resources