learningcs
learningcs

Reputation: 1926

Call method after child executes command

I'm currently learning how to implement Commands into C#/WPF projects. Suppose I have a class MyClass with a simple command MyCommand.

public class MyClass
{
    private RelayCommand _myCommand;
    public ICommand MyCommand
    {
        get
        {
            if (_myCommand == null)
                _myCommand = new RelayCommand(_ => ExecuteMyCommand());
            return _myCommand;
        }
    }

    private void ExecuteMyCommand()
    {
        // Do work...
    }
}

Now, suppose I created an ObservableCollection<MyClass> in a view model, which is bound to a ListView. The ListView has a GridViewColumn with buttons bound to MyCommand. Everything works great.

public class MyViewModel
{
    private ObservableCollection<MyClass> _myCollection;
    public ObservableCollection<MyClass> MyCollection
    {
        get { return _myCollection; }
        set
        {
            _myCollection = value;
            RaisePropertyChanged("MyCollection");
        }
    }

    public void Refresh()
    {
        // Do work to refresh MyCollection to it's "live" state
    }
}

Now I need to call the Refresh() method on the view model after the one of the objects in MyCollection executes MyCommand, but I'm not sure how to approach this situation.

Things I have tried:

Things I have considered:

What would be the best/correct way to approach this problem?

Upvotes: 1

Views: 72

Answers (3)

Brendan
Brendan

Reputation: 41

You can also put a click event on the buttons (they bubble up to the view), and call the command from code-behind

Upvotes: 0

stukselbax
stukselbax

Reputation: 5935

Another way to turn this on is the following:

<MenuItem Content="Run MyCommand"
          Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.RefreshCommand}"
          CommandParameter="{Binding}"/>

Then, in your MyViewModel

public class MyViewModel
{
    private ObservableCollection<MyClass> _myCollection;
    public ObservableCollection<MyClass> MyCollection
    {
        get { return _myCollection; }
        set
        {
            _myCollection = value;
            RaisePropertyChanged("MyCollection");
        }
    }

    //...

    private ICommand _refreshCommand;
    public ICommand RefreshCommand
    {
        get
        {
            if (_refreshCommand== null)
                _refreshCommand= new RelayCommand<MyClass>(p => Refresh(p));
            return _refreshCommand;
        }
    }

    public void Refresh(MyClass parameter)
    {
        if (null == parameter)
            return;
        parameter.ExecuteMyCommand();
        // Do work to refresh MyCollection to it's "live" state
    }
}

Note: currently you do not need to have the MyCommand on each MyClass instance - you can pass it as a parameter to the parent view model.

I cannot say that there is the right way to accomplish your task. So I cannot say which one is better.

Upvotes: 1

learningcs
learningcs

Reputation: 1926

I managed to get this to work in (I think) a pretty nice way.

First of all, I changed Refresh() to a command. I then added a parameter to the MyCommand method. The method does its work, and then checks the parameter to see if it's a command, and then executes it.

private void ExecuteMyCommand(object param)
{
    // Do work...
    if (param != null && param is ICommand)
        ((ICommand)param).Execute(null);
}

Then in XAML for the View, I set the CommandParameter to the command I want it to run afterwards.

<MenuItem Content="Run MyCommand"
          Command="{Binding UploadCommand}"
          CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.RefreshCommand}"/>

If no CommandParameter is supplied in XAML, it passes null. Done...

Upvotes: 0

Related Questions