1
votes

I have DataGridComboBoxColumn that is supposed to show integers or text "Default". When I add row the combobox gets correct value from viewmodel's bound property, but when I change value in user interface, the property's set is not called. I tried both SelectedValueBinding and SelectedItemBinding. Converter's ConvertBack is never called. I don't event know should it be called.

Things that work:

  • DataGrid SelectedItem binding
  • Text column binding both ways (omitted here for shortness)

Here is my code:

XAML:

<DataGrid Name="SelectionSetsGrid" CanUserAddRows="False" CanUserResizeColumns="True" CanUserSortColumns="True" 
                      ItemsSource="{Binding SelectionSets}" AutoGenerateColumns="False"
                      SelectedItem="{Binding SelectedSelectionSet}">
 <DataGrid.Columns>
  <DataGridComboBoxColumn Header="Width" SelectedValueBinding="{Binding LineWidthIndex}">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="ComboBox" BasedOn="{StaticResource Theme.ComboBox.Style}">
            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.LineWidths}"/>
            <Setter Property="IsReadOnly" Value="True"/>
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <WrapPanel>
                            <TextBlock Text="{Binding Converter={StaticResource IntToIntTextOrDefaultConverter}}" VerticalAlignment="Center"/>
                        </WrapPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="ComboBox" BasedOn="{StaticResource Theme.ComboBox.Style}">
            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.LineWidths}"/>
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <WrapPanel>
                            <TextBlock Text="{Binding Converter={StaticResource IntToIntTextOrDefaultConverter}}" VerticalAlignment="Center"/>
                        </WrapPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
  </DataGridComboBoxColumn>
 </DataGrid.Columns>
</DataGrid>

ViewModel (ViewModel implements INotifyPropertyChanged and SetValue raises PropertyChanged):

public class SelectedObjectsViewModel : ViewModel
{
    private int[] _lineWidths = { -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    public ObservableCollection<int> LineWidths { get; private set; };

    private ObservableCollection<SelectionSetViewModel> _selectionSets;
    public ObservableCollection<SelectionSetViewModel> SelectionSets
    {
        get { return _selectionSets; }
        set { this.SetValue(ref _selectionSets, value); }
    }

    private SelectionSetViewModel _selectedSelectionSet;
    public SelectionSetViewModel SelectedSelectionSet
    {
        get { return this._selectedSelectionSet; }
        set { this.SetValue(ref _selectedSelectionSet, value); }
    }
}

ViewModel for DataGrid row (ViewModel implements INotifyPropertyChanged and SetValue raises PropertyChanged):

public class SelectionSetViewModel : ViewModel
{
    public SelectionSetViewModel()
    {
        LineWidthIndex = -1;
    }
    private int _lineWidthIndex;
    public int LineWidthIndex
    {
        get { return _lineWidthIndex; }
        set { SetValue(ref _lineWidthIndex, value); }
    }

Converter:

public class IntToIntTextOrDefaultConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        if ((int)value == -1)
            return Fusion.App.Current.Resources["StrDefault"].ToString();

        return value.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        return value.Equals(true) ? parameter : Binding.DoNothing;
    }
}
1
A lucky quess could be, that the binding needs a Mode=TwoWay?user1562155
sure but none of the examples in web have Mode=TwoWay in DataGridComboBoxColumn binding definition. i tried to put it in 2 different ways but that didn't work. moreover text column works without Mode=TwoWay. if u have an idea how to put it in XAML correctly i would be happy :)char m
Since I have also previously used check box bindings, here is part of my own code: <DataGridCheckBoxColumn Header="some header" Binding="{Binding headerBinding}" Width="80">. Changed the names, but hope this helps.Keyur PATEL

1 Answers

1
votes

It seems that on some occasions like after editing the text column and pressing enter or adding new row the property WAS actually updated (set called) after changing combobox value. So I just added UpdateSourceTrigger=PropertyChanged to binding and the update to source property happened immediately (and not after some random operation). Note that changing focus from ComboBox was not enough to update source property so I thought it was never updated.

<DataGrid Name="SelectionSetsGrid" CanUserAddRows="False" CanUserResizeColumns="True" CanUserSortColumns="True" 
              ItemsSource="{Binding SelectionSets}" AutoGenerateColumns="False"
              SelectedItem="{Binding SelectedSelectionSet}">
        <DataGridComboBoxColumn Header="{StaticResource XpStrTopologyWidth}" SelectedItemBinding="{Binding LineWidthIndex, UpdateSourceTrigger=PropertyChanged}">
            <DataGridComboBoxColumn.ElementStyle>
                <Style TargetType="ComboBox" BasedOn="{StaticResource Theme.ComboBox.Style}">
                    <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.LineWidths}"/>
                    <Setter Property="IsReadOnly" Value="True"/>
                    <Setter Property="ItemTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <WrapPanel>
                                    <TextBlock Text="{Binding Converter={StaticResource IntToIntTextOrDefaultConverter}}" VerticalAlignment="Center"/>
                                </WrapPanel>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DataGridComboBoxColumn.ElementStyle>
            <DataGridComboBoxColumn.EditingElementStyle>
                <Style TargetType="ComboBox" BasedOn="{StaticResource Theme.ComboBox.Style}">
                    <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.LineWidths}"/>
                    <Setter Property="ItemTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <WrapPanel>
                                    <TextBlock Text="{Binding Converter={StaticResource IntToIntTextOrDefaultConverter}}" VerticalAlignment="Center"/>
                                </WrapPanel>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DataGridComboBoxColumn.EditingElementStyle>
        </DataGridComboBoxColumn>                        
    </DataGrid.Columns>
</DataGrid>