Biggles
Biggles

Reputation: 1345

ComboBox DataTemplate in WPF datagrid with binding not initialized

I have a binding list of Models and a DataGrid. Value can be of couple of data types (bool, double).

    public class Model
    {
        public object Value { get; set; }
    }

public void Initialize()
{
            var models = new BindingList<Model>();
            models.Add(new Model(){ Value = "hello"});
            models.Add(new Model(){Value=true});
            signals.ItemsSource = models;
}

I want to display the data in the data grid and I want to use textbox for numbers, but combo(true/false) for boolean values.So I implemented bool2string converter and DataTemplateSelector. In my example I have one text column and one template column displaying the same data. When I start the application the combo values are not initialized (nothing is selected). Once I start playing with values, everything works,the values are properly synchronized (if I change value in one column, it will propagate to the other column). Do you have any idea, what mistake I'm doing?

enter image description here

public class BoolToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((bool)value == true) ? "true" : "false";
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var comboValue = (value as ComboBoxItem).Content.ToString();
        return (String.Compare(comboValue, "true", StringComparison.InvariantCultureIgnoreCase) == 0);
    }
}

public class DynamicDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var element = container as FrameworkElement;
        var signal = item as Model;
        if (element != null && signal != null)
        {
            if (signal.Value is bool)
                return element.FindResource("BoolTemplate") as DataTemplate;
            else
                return element.FindResource("TextTemplate") as DataTemplate;
        }
        return null;
    }
}

My xaml looks like following:

<Window.Resources>
    <comboQuestion:DynamicDataTemplateSelector x:Key="DataTemplateSelector"/>
    <comboQuestion:BoolToStringConverter x:Key="BoolToStringConverter"/>
</Window.Resources>
<Grid>
    <DataGrid Grid.Row="1"  Name="signals" AutoGenerateColumns="False"  ItemsSource="{Binding}" >
        <DataGrid.Resources>
            <DataTemplate x:Key="BoolTemplate">
                <ComboBox SelectedItem="{Binding Value, Converter={StaticResource BoolToStringConverter}, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
                    <ComboBoxItem>true</ComboBoxItem>
                    <ComboBoxItem>false</ComboBoxItem>
                </ComboBox>
            </DataTemplate>
            <DataTemplate x:Key="TextTemplate">
                <TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            </DataTemplate>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Header="TextValue" Binding="{Binding Value}"/>
            <DataGridTemplateColumn Header="DynamicValue" CellTemplateSelector="{StaticResource DataTemplateSelector}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

EDIT: I tried to change the SelectedItem to SelectedValue and I also tried to change the Convert part of the converter to:

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var cbi = new ComboBoxItem();
        cbi.Content = ((bool)value == true) ? "true" : "false";
        return cbi;
    }

however, the behavior remains the same.

Upvotes: 1

Views: 780

Answers (1)

Mike Eason
Mike Eason

Reputation: 9713

You can convert a boolean to an index number using the following converter:

public class BooleanToIndexConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((bool)value == true) ? 0 : 1;   
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((int)value == 0) ? true : false;
        }
    }

Then bind to SelectedIndex on the ComboBox:

SelectedIndex="{Binding Value, Converter={StaticResource BooleanToIndexConverter}}

Upvotes: 1

Related Questions