Commanding in MVVM (WPF)--how to return a value?

2020-06-14 04:18发布

I've been using MVVM pattern for a while now, but I still run into problems in real-life situations. Here's another one: I use commanding and bubble up the event to be handled in the ViewModel. So far, so good. But the project for which I'm using MVVM is actually a class library. Once I run the command code, I need to be able to send an object back to the calling application. What are suggested ways to do so?

Specifically: In my calling app I have a XAML page bound directly to the library's ViewModel, which contains an object "Thing1". When a button is clicked, a method in the ViewModel is called (call it "CopyThing1()"). It copies "Thing1" to create "Thing2". Then I need to send "Thing2" back to the calling app.

Thanks!!!

标签: c# wpf mvvm
4条回答
太酷不给撩
2楼-- · 2020-06-14 04:40

If Thing2 is another property on your viewmodel, you can use normal INotifyPropertyChanged to inform the UI of the change.

You could also use Prism's EventAggregator for a more decoupled approach

查看更多
可以哭但决不认输i
3楼-- · 2020-06-14 05:02

The ideal approach is to define a new class inherited from ICommand as follows:

public abstract class Command2<T1, T2> : ICommand {
    public abstract T2 Execute2(T1 parameter);
}

public class DelegateCommand2<T1, T2> : Command2<T1, T2> {
    public DelegateCommand2(Func<T1, T2> execute, Predicate<T1> canExecute) {
        _execute = execute;
        _canExecute = canExecute;
    }

    public override T2 Execute2(T1 parameter) {
        if (CanExecute(parameter) == false)
            return default(T2);
        else
            return _execute((T1)parameter);
    }
}

Note that Execute2 returns the value just like a normal function. Here is how to use it.

    private readonly ICommand _commandExample = new DelegateCommand2<int, Point3D>(
        commandExample_Executed,
        commandExample_CanExecute
    );

    public Command2<int, Point_3D> CommandExample {
        get {
            return (Command2<int, Point_3D>) _commandExample;
        }
    }

    private static Point3D commandExample_Executed(int index) {
        return Fun1(index); //Fun1 returns a Point_3D
    }

    private static bool commandExample_CanExecute(int index) {
        return true;
    }

Calls Execute2 instead of Execute will returns the value.

查看更多
家丑人穷心不美
4楼-- · 2020-06-14 05:05

Commands don't return values, they change the state of your application. In case of ICommands attached to ViewModels it's pretty simple, because you can do this by simply mutating the ViewModel when the command is executed.

Using the RelayCommand from Josh Smith's excellent MVVM article:

public class MyViewModel : INotifyPropertyChanged
{
    private readonly ICommand mutateCommand;
    private Thing thing;

    public MyViewModel()
    {
        this.mutateCommand = new RelayCommand(this.Mutate);
    }

    public ICommand MutateCommand
    {
        get { return this.mutateCommand; }
    }

    public Thing Thing
    {
        get { return this.thing; }
        set
        {
            this.thing = value;
            // raise PropertyChanged event here...
        }
    }

    private void Mutate(object parameter)
    {
        this.Thing = new Thing();
    }
}

After you call myVM.MutateCommand.Execute(new object()); you can access the new value of myVM.Thing.

查看更多
5楼-- · 2020-06-14 05:06

Although the info on Commanding was clear and correct, it couldn't be applied in my case because the reponse required to happen was in a calling application NOT using MVVM and it was not to be UI response only. I did investigate Prism, but found it too complex for what I need at the moment. I ended up raising and handling events, as described here--> WPF MVVM Correct Way to Fire Event on View From ViewModel

查看更多
登录 后发表回答