Search code examples
c#mvvmcomboboxbindingexpression-blend

Adding new element to a ComboBox which is in a DataGrid in WPF using MVVM


I have a DataGrid which contains Transactions. I have an InterestOrDividend column where I can select a value using a ComboBox. This works fine.

A new feature would be to enter a value and add it to the list of possibilities. I set IsEditable to true and added Interaction.Triggers from http://schemas.microsoft.com/expression/2010/interactivity

Problem 1: It seems InterestOrDividendSelectionChangedCommand not only fires when the selection is changed but also when I scroll the DataGrid and such rows come into view which has a not null value in the InterestOrDividend column. Moreover, when a new value is entered (which is not in the list), the event does not fire.

Problem 2: I want to bind the Text property of the ComboBox to get the newly added value. It seems the event fire before the Text property changes, so I get the old value.

<DataGridTemplateColumn Header="{x:Static r:Resource.InterestOrDividend}"
   CellTemplate="{StaticResource InterestOrDividendEditingTemplate}"
   CellEditingTemplate="{StaticResource InterestOrDividendEditingTemplate}" />

<DataTemplate x:Key="InterestOrDividendEditingTemplate">
        <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, 
                            AncestorType={x:Type DataGrid}}, Path=DataContext.AppData.AlienTypeObjects}" 
                  SelectedItem="{Binding InterestOrDividend}" 
                  DisplayMemberPath="FullName" 
                  IsEditable="True" 
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource FindAncestor, 
                        AncestorType={x:Type DataGrid}}, 
                        Path=DataContext.InterestOrDividendSelectionChangedCommand}"
                        CommandParameter="{Binding RelativeSource={RelativeSource  FindAncestor, 
                        AncestorType={x:Type ComboBox}}, Path=Text}"
                                           />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
</DataTemplate>

Solution

  • This is my solution.

    • if an existing Category is selected then SelectedItem is updated

    • if a new Category is typed then the new category is created based on the Text property

    • the NewCategory is updated at PropertyChanged so at Category setting the NewCategory is ready

      • if LostFocus is used then there is no guarantee that NewCategory is set before Category
    • NewCategory uses OneWayToSource mode else the SelectedItem is set but the Text is overwritten to null

      • the inital value is not displayed in the ComboBox
    • DoNotNotify is needed else the Refresh button will be always red at the Transaction tab

      • NewCategory is only a helper property of DisplayTransaction

                    <DataTemplate x:Key="CategoryEditingTemplate">
                        <ComboBox VerticalContentAlignment="Center" DisplayMemberPath="FullName"
                                  IsEditable="True"
                                  ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.CollectionAndDefault.CategoryObjects}"
                                  SelectedItem="{Binding Category, UpdateSourceTrigger=LostFocus}"
                                  Style="{StaticResource ComboBoxError}"
                                  Text="{Binding NewCategory, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"
                                  ToolTip="{Binding Category.FullName}" />
                    </DataTemplate>