WPF bound combobox using converter - wpf

I have a ComboBox that is bound to an EnumerableRowCollection<T> :
ComboFamilyStatus.ItemsSource = EnumerableRowCollection<TaxDataSet.SourcesOfValuesRow> coll;
My xaml lookes like this:
<ComboBox Name="ComboFamilyStatus" DisplayMemberPath="Description"
Text="{Binding FamilyStatus, Converter={StaticResource FamilyStatusStringConverter}}">
I'm using the DisplayMemberPath to show the description of the row. The SourcesOfValuesRow has a value and a description and in the combo I want to see the description text. The Text is bound to the database where the FamilyStatus is saved as an int value this is why I added a converter.
My question is if the converter could convert from the int value to the string using the itemsource from the combobox? I don't see that the converter knows anything about the combo. In the meantime I wrote the converter to take again the EnumerableRowCollection<TaxDataSet.SourcesOfValuesRow> from the database and find there the matched description - this can't be the simplest way to do this!
Any suggestions??

In this case, you're better off using a DataTemplate, instead of a Converter.
You already have a data class. Just use a DataTemplate that inserts a Textblock bound to the int value, then apply your converter there.
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:TaxDataSet.SourcesOfValuesRow}">
<TextBlock Text="{Binding FamilyStatus, Converter={StaticResource FamilyStatusStringConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox>
Change your SourcesOfValuesRow FamilyStatusProperty to an enum. Deriving from int lets you cast it directly.
enum FamilyStatusValues : int
{
[Description("Married")]
Married,
[Description("Divorced")]
Divorced,
[Description("Living Together")]
LivingTogether
}
Then in your converter use this code
ConvertTo(object value, ...)
{
FieldInfo field = value.GetType().GetField(value.ToString());
object[] attribs = field.GetCustomAttributes(typeof(DescriptionAttribute), true));
if(attribs.Length > 0)
{
return ((DescriptionAttribute)attribs[0]).Description;
}
return string.Empty;
}

There is no need to use any converter. It worked for me using this:
<ComboBox Name="FamilyStatus" Grid.Row="7" Grid.Column="1" ItemsSource="{Binding Source={StaticResource comboProvider}}"
SelectedValuePath="Value" DisplayMemberPath="Description" SelectedValue="{Binding FamilyStatus}">
Where DisplayMemberPath is the string from the TaxDataSet.SourcesOfValuesRow and SelectedValuePath is the int value. The SelectedValue is the value from the contact table (instead of writing in the combo Text="{Binding FamilyStatus, Converter={StaticResource FamilyStatusStringConverter}}).

Related

wpf comboBox selectedIndex=0 is not working

.xaml
<ComboBox Grid.Row="0" Grid.Column="1" x:Name="cbx_srchResOrg" HorizontalAlignment="Stretch" Style="{DynamicResource ComboBoxStyle}"
ItemsSource="{Binding InfoCombo}" SelectedIndex="0" DisplayMemberPath="Dis_name" SelectedValuePath="Hide_id" SelectedItem="{Binding SelectInfo}"/>
Here is a part of my source code.
Why 'SelectedIndex=0' is not working?
I want to select [0] value to default at first time, but it just empty box at run time. There are no errors except it. How can I fix it?
As Hej said, you have binded the SelectedItem with a property in your view model which was null.
You can fix this by assigning the SelectedItem in your Viewmodel constructor
Public MyViewModel()
{
SelectInfo = InfoCombo[0];
}
Because you are already binding to SelectedItem. It binds two way by default, so if the property binded to it(SelectInfo) is null, it will also be set to null.
You can also use Mode=OneWayToSource in the SelectedItem binding with SelectedIndex="0".
In your case:
<ComboBox Grid.Row="0"
Grid.Column="1"
x:Name="cbx_srchResOrg"
HorizontalAlignment="Stretch"
Style="{DynamicResource ComboBoxStyle}"
ItemsSource="{Binding InfoCombo}"
SelectedIndex="0"
DisplayMemberPath="Dis_name"
SelectedValuePath="Hide_id"
SelectedItem="{Binding SelectInfo, Mode=OneWayToSource}"/>
Like others said, it binds two way by default, so if the property binded to it (SelectInfo) is null, it will also be set to null.
you have bind SelectedItem to SelectInfo, you should set value(in your viewmodel) to SelectInfo as default, for example
SelectInfo = InfoCombo[0] or something other whatevere you want to set as default value

MVVM WPF - ComboBox two way binding inside ItemsControl

I am working on this problem for about a day now.
For some reason I am unable to TwoWay bind a value to a ComboBox if it is inside a ItemsControl. Outside works just fine.
I have an ObservableCollection of int? in my ViewModel:
private ObservableCollection<int?> _sorterExitsSettings = new ObservableCollection<int?>();
public ObservableCollection<int?> SorterExitsSettings
{
get { return _sorterExitsSettings; }
set
{
if (_sorterExitsSettings != value)
{
_sorterExitsSettings = value;
RaisePropertyChanged("SorterExitsSettings");
}
}
}
My XAML:
<ItemsControl ItemsSource="{Binding SorterExitsSettings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}, Path=DataContext.ScanRouter.Stores}"
SelectedValue="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="name" SelectedValuePath="id" IsEditable="True" />
</DataTemplate>
</ItemsControl.ItemTemplate>
So the ComboBox is populated with a list of stores. It works fine so far.
The ObservableCollection SorterExitsSettings even has some values set which are shown in the displayed ComboBoxes. So setting the SelectedValue also works.
However when I change a selection, SorterExitsSettings wont change. While when I implement the ComboBoxes(100) without an ItemsControl it suddenly works fine.
<ComboBox ItemsSource="{Binding ScanRouter.Stores}" DisplayMemberPath="name" SelectedValuePath="id" IsEditable="True" SelectedValue="{Binding SorterExitsSettings[0], Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Even better when I implement the ComboBoxes using the ItemsControl and also the example ComboBox shown above. When I change the single ComboBox's value it will change the value of the ComboBox inside the ItemsControl, but not the other way around.
Did somebody encounter this problem before?
My guess was that the ItemsControl doesn't like the fact that I am binding my selected value to an item in a list. However when I bind directly to a ViewModel property(Store) it also doesn't work.
I also tried using SelctedItem instead of SelectedValue and populate the ObservableCollection with Store objects instead of int?.
The problem is that you're binding your ComboBox's SelectedValue directly to the collection elements which are type int ?. This won't work, binding targets have to be properties. Try wrapping your int ? values in a class and expose the value as a property of that class with a getter and setter, i.e. something like this:
private ObservableCollection<Wrapper> _sorterExitsSettings = new ObservableCollection<Wrapper>();
... etc...
And:
public class Wrapper
{
public int? Value {get; set;}
}
And finally:
<ComboBox ... SelectedValue="{Binding Path=Value, Mode=TwoWay...
Post back here if you still have problems.

Why is binding this DataGrid's ItemsSource to collection of anonymous types not working?

I have a collection of anonymous types that I wish to bind to the ItemsSource property of a DataGrid. I confirmed the collection has items, but my DataGrid is empty.
I created a Debug converter and it does not hit my breakpoint in there so it appears something is going awry before that point.
I checked my Output window, and I see no binding errors.
My anonymous type looks something like this:
var cars = from c in something.Cars
select new
{
Passengers = from p in c.Passengers
select new
{
Name = p.Name
}
Type = s.Type
};
Cars = cars;
After this point, I checked the contents of Cars and it does have data.
My Xaml looks something like this:
<TabControl ItemsSource="{Binding Cars}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Type}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<DataGrid ItemsSource="{Binding Passengers}" >
<!-- column definitions here -->
</DataGrid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
The TextBlock binding on Type does display the correct data.
What am I missing?
UPDATE:
The type of the linq result is System.Linq.Enumerable.WhereSelectListIterator. I have another DataGrid, where the binding to anonymous types work, but I noticed the linq result of type System.Linq.Enumerable.WhereSelectEnumerableIterator.

What is normally bound to a wpf combobox

I want to bind something to a combobox that will display something different than it's value.
What would be the suggested/most common data container to link the combobox to? Would it be a custom type and then do a list of that type? A data table? I am using vb.net and wpf. The list would be something like:
dog,1
cat,2
bird,3
fish,4
The combobox would display the animal name and the value would be the number. The data to populate the combobox will come from a MYSql database.
Set the DisplayMemberPath on your Combobox to the property of the underlying object you want to
display.
So assuming you have an object like this:
Public Class Animal
{
string Name {get;set;}
int Number {get;set;}
}
You would set your DisplayMemberPath to Name.
Else check out this link for a more complete answer:
Binding WPF ComboBox to a Custom List
You can populate with anything you want, you can also display multiple items like so
<ComboBox ItemsSource{Binding ItemList}>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding AnimalName}" />
<Checkbox IsChecked={Binding SelectAnimal}" Content="{Binding Age}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The Select animal is just so you can get an idea of doing a template

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.

Resources