1

I have following xaml:

<DataGridTemplateColumn Header="123">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Role}"/>
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
        <ComboBox ItemsSource="{Binding Path=DataContext.Roles, 
                  RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding Path = DataContext.UpdateUserCommand}" /> // bind fails there
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
    </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

The problem is that my command is not running on change, but if move combobox definition out of datagrid, my command is firing successfully. Seems like my bindging wrong, but i can't figure out what's wrong.

Nicefsf
  • 140
  • 1
  • 1
  • 9
  • Why don't you just bind the SelectedItem property of the ComboBox to a view model property? – Clemens May 02 '20 at 10:52
  • I need to do async stuff on this event, for me binding to a event is the only possible solution. After i change selected item i want to start async db updation via my service – Nicefsf May 02 '20 at 10:54
  • You could register an async PropertyChanged event handler in your view model, to react on its own property change... – Clemens May 02 '20 at 10:56
  • @Clemens rather modify the PropertyChanged event raiser. binding to your own events makes not much sense – Welcor May 02 '20 at 11:00
  • @Clemens that seems to be a more cleaner solution, but i didn't find any example of doing it, i don't have much experience working with events so i'm not sure how to implement this – Nicefsf May 02 '20 at 11:02
  • Just something like this in the view model `this.PropertyChanged += async (s, e) => { if (e.PropertyName == "SelectedItem") { await SomeAsyncAction(); }};` – Clemens May 02 '20 at 11:13
  • @Blechdose That is not possible without violating the rule that every async method should be awaited, except event handlers, which are allowed to be `async void` – Clemens May 02 '20 at 11:17
  • @Clemens that seems working for me, thanks. You can post is as solution and i will flag it as an answer or at least mark as usefull – Nicefsf May 02 '20 at 11:19
  • @Clemens implementing it into the event raiser or using an event handler has exactly the same effect in this case. Except using the event handler makes not much sense because the class already owns the event itself. both will violate the rule anyway. it will be in both cases fire and forget. this sounds a lot like "follow a principle without understanding why it exists". https://stackoverflow.com/a/7825063/4394435 – Welcor May 02 '20 at 11:24

2 Answers2

1

Just bind the ComboBox's SelectedItem property to a SelectedRole property in your view model.

In order to run an async action when the view model property changes, just attach an async PropertyChanged event handler in the view model:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public ViewModel()
    {
        PropertyChanged += async (s, e) =>
        {
            if (e.PropertyName == nameof(SelectedRole))
            {
                await SomeAsyncAction();
            }
        };
    }

    private Role selectedRole;

    public Role SelectedRole
    {
        get { return selectedRole; }
        set
        {
            selectedRole = value;
            PropertyChanged?.Invoke(this,
                new PropertyChangedEventArgs(nameof(SelectedRole)));
        }
    }

    private async Task SomeAsyncAction()
    {
        ...
    }
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
0

You could try this (not 100% sure it'll work because cannot see all of your code)

<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=DataContext.UpdateUserCommand}" />
Dean Chalk
  • 20,076
  • 6
  • 59
  • 90
  • It still not working. I've already tried your approach. Let me now which part of the code you want to see so i can edit my question – Nicefsf May 02 '20 at 10:51