Data Binding in Combobox - wpf

I binded a database table's primary key to the selectedIndex of a combobox. the problem occurs where the primary key starts from 1 but selectedIndex accepts from 0. I mean, when I want to see the item with ID=1 in database, since it's listed as first element in combobox with index 0, it displays the second element in the list, which is considered with ID=1 in the combobox. Can anyone help me on solving this problem?
Thanks in advance.
here's my combobox:
<ComboBox SelectedIndex="{Binding SC.User1.UserID, UpdateSourceTrigger=PropertyChanged }"
IsSynchronizedWithCurrentItem="True"
x:Name="proxyResponsibleUserCmb" ItemsSource="{Binding Users, Mode=OneTime}"
SelectedItem="{Binding SC.User1.FullName, ValidatesOnDataErrors=True,
UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{x:Null}"
Height="23"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="118"
Margin="184,3,0,0"
Grid.Row="0"
Grid.Column="1"/>

What about using the ComboBox's SelectedValuePath and DisplayMemberPath, and setting your default item with SelectedValue instead of SelectedItem?
<ComboBox x:Name="proxyResponsibleUserCmb"
SelectedValuePath="{Binding UserID}"
DisplayMemberPath="{Binding FullName}"
SelectedValue="{Binding SC.User1.UserId, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Users, Mode=OneTime}" />

Does setting the property IsSynchronizedWithCurrentItem (in your XAML) to True help?
EDIT
Maybe this link will help:
http://social.msdn.microsoft.com/Forums/en/wpf/thread/b4e84ea2-9597-4af1-8d3c-835b972e3d73

Quick workaround via a ValueConverter:
Create a ValueConverter in your codebehind:
// of course use your own namespace...
namespace MyNameSpace
{
public class IndexConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(!(value is int)) // Add the breakpoint here!!
throw new Exception();
int newindex = ((int)value - 1;
return newindex;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("This method should never be called");
}
}
}
Then, make it known in your XAML:
//(declare a namespace in your window tag:)
xmlns:myNamespace="clr-namespace:MyNameSpace"
// add:
<Window.Resources>
<ResourceDictionary>
<myNamespace:IndexConverter x:Key="indexConverter" />
</ResourceDictionary>
</Window.Resources>
Then change your binding:
<ComboBox SelectedIndex="{Binding SC.User1.UserID, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource indexConverter}}" ... />
That should do the trick. At least you can debug it by inserting a breakpoint in the IndexConverter.

Related

Disabling/Making read only all combobox in one column in datagrid

My grid is getting bound correctly all I have to do is disable or make it readonly all the combobox contained in the Column2 based on any condition from code behind. suppose after the grid is rendered we get 10 rows containing this comboxbox. I have to disable the combobox column in all these 10 rows.
<DataGridTextColumn Binding="{Binding Value1}" Header="Column1" IsReadOnly="True"/>
<DataGridTemplateColumn Header="Column2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding MySelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding MyComboItemSource}" >
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGridTextColumn>
You just need to make a bool property in the Code-Behind and bind to the isEnabled property of the combobox in the xaml.
Code-Behind
private bool _Disable;
public bool Disable
{
get { return _Disable; }
set
{
_Disable= value;
OnPropertyChanged("Disable");
}
}
Xaml
<ComboBox IsEnabled="{Binding Disable,Mode=TwoWay,RelativeSource={RelativeSource AncestorType=Window}}" SelectedItem="{Binding MySelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding MyComboItemSource}" >
You can use a Converter for the property IsEnabled in the combobox.
Something like
<ComboBox IsEnabled ={Binding Path=XXXX, Converter = {StaticResource MyConverter}} .... />
MyConverter will chech the property you want and retrieve false or true.
Something like this:
public class MyConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(value!=null)
{
if((int) value==1)
return true;
else return false;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

WPF binding TextBox and ObservableDictionary<Int64,String> (display String by Id)

Each item of my Employee's list has Post property. This property is Int64 type. Also, I have some ObservableDictionary<Int64,String> as static property. Each Employe must display the String value by its key.
DataTemplate for Employe item (I deleted the superfluous):
<DataTemplate x:Key="tmpEmploye">
<Border BorderThickness="3" BorderBrush="Gray" CornerRadius="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=Post}"/>
</StackPanel>
</Border>
</DataTemplate>
But this code displayed the Int64 value, not the String. String for getting static dictionary:
"{Binding Source={x:Static app:Program.Data}, Path=Posts}"
I know how solve it problem for ComboBox, but I don't know for TextBlock. For ComboBox I wrote it (it is works fine):
<ComboBox x:Name="cboPost" x:FieldModifier="public" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Margin="2" Grid.ColumnSpan="2"
ItemsSource="{Binding Source={x:Static app:Program.Data}, Path=Posts}" DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding Path=Post, Mode=TwoWay}">
</ComboBox>
But how can I solve it for TextBlock?
mmmmm, I'm sure I have developed something for this scenario before but I can't remember or find anything related!
IMO you can use a converter, so you pass your Post (Int64) to the converter and it returns the string value from the dictionary, although it must be a better solution.
[ValueConversion(typeof(Int64), typeof(string))]
public class PostToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// validation code, etc
return (from p in YourStaticDictionary where p.Key == Convert.ToInt64(value) select p.Value).FirstOrDefault();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
}
}
XAML:
<Window ...
xmlns:l="clr-namespace:YourConverterNamespace"
...>
<Window.Resources>
<l:PostToStringConverter x:Key="converter" />
</Window.Resources>
<Grid>
<TextBlock Text="{Binding Post, Converter={StaticResource converter}}" />
</Grid>
</Window>

WPF Combobox bind text

Maybe a simple task but I can't find the solution. I have a combobox connected to a database. Instead of displaying the content of ProductLookup I just want to display the words 'male' and 'female' on the popup menu.
Thank you
<ComboBox Height="23" Name="ComboBox2" Width="120" IsEditable="False"
ItemsSource="{Binding Source={StaticResource ProductLookup}}"
SelectedValue="{Binding Path=ProductID}"
SelectedValuePath="ProductID"
DisplayMemberPath="Name"/>
Write a Converter that takes one of your "Product" objects....looks at the gender related data inside it, or does the gender determining logic, and then returns the gender string, "male" or "female".
Then use it in your XAML to set the TextBlock:
<StackPanel Height="197" HorizontalAlignment="Left" Margin="300,6,0,0" Name="StackPanel5" VerticalAlignment="Top" Width="285"
DataContext="{Binding Source={StaticResource DetailViewPagos}}">
<StackPanel.Resources>
<local:ProductToGenderConverter x:Key="prodtogenderconv"/>
</StackPanel.Resources>
<ComboBox Height="23" Name="ComboBox2" Width="120" IsEditable="False"
ItemsSource="{Binding Source={StaticResource ProductLookup}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource prodtogenderconv}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
public class ProductToGenderConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
MyProduct prod = value as MyProduct;
if (prod is for a male) // Pseudocode for condition
return "male";
if (prod is for a female) // Pseudocode for condition
return "female";
return null or "";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
Alternatively you could provide a ViewModel which wraps your Product object, which has a specific property that indicates the "genderness" of the Product...then create a collection of those objects for setting in your ComboBox...then you can use DisplayMemberPath to point to that property.
Please see this answer, it is a way to wrap your values for nice binding and display in WPF.
The Item class could be modified to support object for the Code property.

Bind IsChecked of a CheckBox to a method

Is it possible to bind the IsChecked property of a checkbox to a custom method?
I created a list of checkboxes bound to a collection of objects. I have a second collection of objects which is a subset of the first one. I'd like to bind the IsChecked porperty of the checkbox to a method that determines if the object is contained in the second list or not
EDIT:
<ListBox Height="auto" HorizontalAlignment="Stretch" Name="listBox" VerticalAlignment="Stretch" Width="auto" ItemsSource="{Binding DataSources}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="CheckBoxZone"
Content="{Binding Name}"
Tag="{Binding Id}"
Margin="0,5,0,0"
/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can bind the checkbox Command property to a ICommand on your model. This means every time the check is changed the command will be invoked.
Example:
<CheckBox Name="CheckBoxZone"
Content="{Binding Name}"
Tag="{Binding Id}"
Margin="0,5,0,0"
Command={Binding CheckBoxChangedCommand}
/>
You may bind IsChecked to both the data object and the subset collection by means of a MultiBinding in conjunction with a multi-value converter that converts into a bool (or Nullable<bool> for IsChecked) value:
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource ObjectInListConverter}" Mode="OneWay">
<Binding />
<Binding Source="{StaticResource SubsetCollection}" />
</MultiBinding>
</CheckBox.IsChecked>
The converter:
class ObjectInListConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
IList subset = values[1] as IList;
Nullable<bool> result = subset.Contains(values[0]);
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
In addition to Pop Catalin's answer, you will want to bind IsChecked to a property in the VM and modify that VM property when command is executed.

Binding to ComboBox with converter in Silverlight

I have a numeric value that I wish to be converted to a more user-friendly string format when it's displayed. I already have an IValueConverter called FlightLevelConverter that I'm using to do this for a normal TextBlock UI item where it works fine.
I now wish to apply the converter to a ComboBox of altitude choices, but I can't get it to work.
This is the relevant part of the XAML I'm using for the ComboBox:
<UserControl.Resources>
<status:FlightLevelConverter x:Key="FlightLevelConverter"/>
</UserControl.Resources>
...
<ComboBox x:Name="AltitudeCombo" Grid.Row="0" Grid.Column="3" Width="100">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource FlightLevelConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
It displays the un-converted numeric values, not the nice string values. I get no errors and if I set a breakpoint in the converter it doesn't get hit, showing that the converter is never called.
I've spent all morning trawling the Internet in general and StackOverflow in particular to try to discover what I'm doing wrong, but haven't found out anything useful.
Why is my converter not being called? What am I doing wrong?
How do you add the items to the ComboBox?
You should set the ItemsSource property to a collection of numeric values, e.g.
List<double> values = new List<double>();
values.Add(2.1);
values.Add(3.2);
values.Add(4.3);
values.Add(5.4);
AltitudeCombo.ItemsSource = values;
If you add ComboBoxItems like this
AltitudeCombo.Items.Add(new ComboBoxItem() { Content = 1.4 });
the ItemTemplate and hence the binding with its converter won't be applied.
Here is a short working sample. You can compare code...
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:bys="clr-namespace:WpfApplication1"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<bys:MyList x:Key="lst"/>
<bys:MyConverter x:Key="myConverter"/>
</Grid.Resources>
<ComboBox ItemsSource="{StaticResource lst}" SelectedIndex="0">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource myConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox >
</Grid>
</Window>
C#:
public class MyList : List<int> {
public MyList() {
AddRange(new[] { 1, 2, 3, 4, 5, 6 });
}
}
public class MyConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return String.Format("<<{0}>>", value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
ComboBox.ItemTemplate is not applicable to the main part of the ComboBox if ComboBox.IsEditable == true. It works for dropdown list entries only. Try to set ComboBox.IsEditable == false. It might help.

Resources