source

ICommand MVVM 구현

itover 2023. 4. 22. 09:21
반응형

ICommand MVVM 구현

이 MVVM 구현에서는 몇 가지 명령어가 필요합니다.ICOMMAND 수업을 하나하나 실시하는 것에 싫증이 나서 해결책을 생각해 냈습니다만, 그것이 얼마나 좋은지 알 수 없기 때문에, 여기 있는 WPF 전문가라면 가르쳐 주세요.그리고 더 나은 솔루션을 제공할 수 있다면 더 좋을 것입니다.

이 작업은 하나의 ICommand 클래스와 2명의 딜러가 객체를 매개 변수로 사용하므로 한 딜러는 무효(OnExecute의 경우)이고 다른 딜러는 Bool(OnCanExecute의 경우)입니다.따라서 ICMand(ViewModel 클래스로 호출됨)의 컨스트럭터에서 두 가지 메서드를 전송하고 각 ICOMMand 메서드에서 딜러의 메서드를 호출합니다.

정말 잘 먹히긴 하는데 이게 나쁜 방법인지 아니면 더 나은 방법이 있는지 모르겠어요.아래는 완전한 코드입니다.입력해주시면 감사하겠습니다.부정적이시더라도요.

뷰 모델:

public class TestViewModel : DependencyObject
{
    public ICommand Command1 { get; set; }
    public ICommand Command2 { get; set; }
    public ICommand Command3 { get; set; }

    public TestViewModel()
    {
        this.Command1 = new TestCommand(ExecuteCommand1, CanExecuteCommand1);
        this.Command2 = new TestCommand(ExecuteCommand2, CanExecuteCommand2);
        this.Command3 = new TestCommand(ExecuteCommand3, CanExecuteCommand3);
    }

    public bool CanExecuteCommand1(object parameter)
    {
        return true;
    }

    public void ExecuteCommand1(object parameter)
    {
        MessageBox.Show("Executing command 1");
    }

    public bool CanExecuteCommand2(object parameter)
    {
        return true;
    }

    public void ExecuteCommand2(object parameter)
    {
        MessageBox.Show("Executing command 2");
    }

    public bool CanExecuteCommand3(object parameter)
    {
        return true;
    }

    public void ExecuteCommand3(object parameter)
    {
        MessageBox.Show("Executing command 3");
    }
}

IC 모드:

public class TestCommand : ICommand
{
    public delegate void ICommandOnExecute(object parameter);
    public delegate bool ICommandOnCanExecute(object parameter);

    private ICommandOnExecute _execute;
    private ICommandOnCanExecute _canExecute;

    public TestCommand(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod)
    {
        _execute = onExecuteMethod;
        _canExecute = onCanExecuteMethod;
    }

    #region ICommand Members

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute.Invoke(parameter);
    }

    public void Execute(object parameter)
    {
        _execute.Invoke(parameter);
    }

    #endregion
}

이것은 Karl Shifflet이 증명한 과 거의 같다.RelayCommand,어디에Execute소정의 발화Action<T>최고의 해결책이라고 할 수 있죠

public class RelayCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public RelayCommand(Predicate<object> canExecute, Action<object> execute)
    {
        _canExecute = canExecute;
        _execute = execute;
    }

    public event EventHandler CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

이것은, 다음의 경우에 사용할 수 있습니다.

public class MyViewModel
{
    private ICommand _doSomething;
    public ICommand DoSomethingCommand
    {
        get
        {
            if (_doSomething == null)
            {
                _doSomething = new RelayCommand(
                    p => this.CanDoSomething,
                    p => this.DoSomeImportantMethod());
            }
            return _doSomething;
        }
    }
}

상세보기:
Josh Smith (소개자)RelayCommand): 패턴 - MVVM 설계 패턴을 사용한WPF 어플리케이션

ICOMMand 인터페이스에 대해 이 기사를 썼습니다.

아이디어 - 두 명의 딜러가 참여하는 범용 명령어 작성: 하나는 다음 경우에 호출됩니다.ICommand.Execute (object param)두 번째는 명령어를 실행할 수 있는지 여부를 확인합니다.(ICommand.CanExecute (object param)).

이벤트를 전환하는 메서드가 필요합니다.CanExecuteChanged상태를 전환하기 위해 사용자 인터페이스 요소에서 호출됩니다.CanExecute()명령어를 입력합니다.

public class ModelCommand : ICommand
{
    #region Constructors

    public ModelCommand(Action<object> execute)
        : this(execute, null) { }

    public ModelCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    #endregion

    #region ICommand Members

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return _canExecute != null ? _canExecute(parameter) : true;
    }

    public void Execute(object parameter)
    {
        if (_execute != null)
            _execute(parameter);
    }

    public void OnCanExecuteChanged()
    {
        CanExecuteChanged(this, EventArgs.Empty);
    }

    #endregion

    private readonly Action<object> _execute = null;
    private readonly Predicate<object> _canExecute = null;
}

방금 전에 구성 스타일에 대해 관례적으로 명령을 구현하는 방법을 보여 주는 간단한 예를 만들었습니다.그러나 Reflection이 필요합니다.Exmiss()를 사용할 수 있습니다.보조 코드가 좀 이상할 수 있지만 한번 작성하면 여러 번 사용할 수 있습니다.

티저:

public class SampleViewModel: BaseViewModelStub
{
    public string Name { get; set; }

    [UiCommand]
    public void HelloWorld()
    {
        MessageBox.Show("Hello World!");
    }

    [UiCommand]
    public void Print()
    {
        MessageBox.Show(String.Concat("Hello, ", Name, "!"), "SampleViewModel");
    }

    public bool CanPrint()
    {
        return !String.IsNullOrEmpty(Name);
    }
}

}

업데이트: 현재 ICOMMand 보일러 플레이트 코드 문제를 해결하는 http://www.codeproject.com/Articles/101881/Executing-Command-Logic-in-a-View-Model과 같은 라이브러리가 있는 것 같습니다.

@Carlo 저는 당신의 구현이 매우 마음에 듭니다만, 제 버전이나 View Model에서의 사용법을 공유하고 싶었습니다.

첫 번째 구현 ICommand

public class Command : ICommand
{
    public delegate void ICommandOnExecute();
    public delegate bool ICommandOnCanExecute();

    private ICommandOnExecute _execute;
    private ICommandOnCanExecute _canExecute;

    public Command(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod = null)
    {
        _execute = onExecuteMethod;
        _canExecute = onCanExecuteMethod;
    }

    #region ICommand Members

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute?.Invoke() ?? true;
    }

    public void Execute(object parameter)
    {
        _execute?.Invoke();
    }

    #endregion
}

파라미터가 ICommandOnExecuteICommandOnCanExecute에서 삭제되고 null이 컨스트럭터에 추가되었습니다.

그런 다음 ViewModel에서 사용합니다.

public Command CommandToRun_WithCheck
{
    get
    {
        return new Command(() =>
        {
            // Code to run
        }, () =>
        {
            // Code to check to see if we can run 
            // Return true or false
        });
    }
}

public Command CommandToRun_NoCheck
{
    get
    {
        return new Command(() =>
        {
            // Code to run
        });
    }
}

변수를 할당하고 인스턴스화할 필요가 없기 때문에 한 번에 모든 작업을 수행할 수 있기 때문에 이 방법이 더 깨끗합니다.

언급URL : https://stackoverflow.com/questions/1468791/icommand-mvvm-implementation

반응형