programing

MVVM 매드니스: 명령

oldcodes 2023. 5. 24. 22:21
반응형

MVVM 매드니스: 명령

MVVM을 좋아합니다.저는 그것을 사랑하지 않지만, 하지만 좋아합니다.대부분 말이 됩니다.하지만, 저는 당신이 XAML을 쓸 수 있고 코드 뒤에 코드를 쓸 필요가 없도록 코드를 많이 작성하도록 격려하는 기사를 계속 읽고 있습니다.

예를 하나 들어보죠.

최근에 View 모델의 명령을 ListView Mouse DoubleClick Event에 연결하려고 했습니다.어떻게 해야 할지 잘 몰랐습니다.다행히도, 구글은 모든 것에 대한 답을 가지고 있습니다.다음 문서를 찾았습니다.

솔루션이 명령을 이해하는 데 도움이 되었지만 문제가 있었습니다.위에서 언급한 솔루션 중 일부는 종속성 속성 뒤에 "Internal"을 추가하는 일반적인 해킹 때문에 WPF 디자이너를 사용할 수 없게 만들었습니다. WPF 디자이너는 찾을 수 없지만 CLR은 찾을 수 있습니다.일부 솔루션에서는 여러 명령에서 동일한 제어를 허용하지 않았습니다.일부 솔루션에서 매개 변수를 허용하지 않았습니다.

몇 시간 동안 실험한 후에 저는 이것을 하기로 결정했습니다.

private void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
    ListView lv = sender as ListView;
    MyViewModel vm = this.DataContext as MyViewModel;

    vm.DoSomethingCommand.Execute(lv.SelectedItem);
}

MVVM 순수주의자 여러분, 이것이 무엇이 문제인지 말씀해 주시겠습니까?아직 유닛 테스트가 가능합니다.이것은 매우 실용적으로 보이지만, "ZOMG... 코드 뒤에 코드가 있습니다!"라는 지침을 위반하는 것처럼 보입니다.소감 부탁드립니다.

잘 부탁드립니다.

저는 그 결함이 순도 요건에 있다고 생각합니다.MVVM을 포함한 설계 패턴은 도구 상자의 도구이지 도구 자체의 목적이 아닙니다.잘 고려된 사례에 대한 모델의 순도와 구분하는 것이 더 타당하다면(그리고 분명히 이 사례를 고려한 것처럼 보입니다), 모델과 구분합니다.

만약 그것이 당신에게 효과가 있고, 그것이 과도한 유지관리 부담이라고 생각하지 않는다면, 저는 당신이 한 일에 아무 문제가 없다고 말할 것입니다.순수한 MVVM 구현이 무엇이든 간에 문제에 대한 합리적인 솔루션임을 입증해야 하는 부담을 분명히 충족했다고 생각합니다.

(저는 이 주장이 다중 패러다임 언어에 대한 주장과 유사하다고 생각합니다.Pure OOO 접근 방식을 적용할 수는 있지만, 때로는 좀 더 기능적인 방식으로 작업을 수행하는 것이 더 적절합니다.순수 기능적 접근 방식을 적용할 수는 있지만, 때로는 절충을 통해 OOO 기술이 그 이상의 가치가 있다는 것을 알 수 있습니다.)

많은 MVVM-Command 솔루션이 너무 복잡하다는 데 동의합니다.개인적으로 혼합 접근 방식을 사용하고 View Model의 메서드와 속성을 사용하여 View Model이 아닌 View에서 명령을 정의합니다.

XAML:

<Window.Resources>
    <RoutedCommand x:Key="LookupAddressCommand" />
</Window.Resources>
<Window.CommandBindings>
    <CommandBinding Command="{StaticResource LookupAddressCommand}" x:Name="cmdLookupAddress" />
</Window.CommandBindings>

코드(보기):

Private Sub cmdLookupAddress_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs) Handles cmdLookupAddress.CanExecute
    e.CanExecute = myViewModel.SomeProperty OrElse (myViewModel.SomeOtherProperty = 2)
End Sub

Private Sub cmdLookupAddress_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs) Handles cmdLookupAddress.Executed
    myViewModel.LookupAddress()
End Sub

순수 MVVM은 아니지만 간단하며, 작동하며, 특별한 MVVM 명령 클래스가 필요하지 않으며, 비 MVVM 전문가(= 내 동료)가 코드를 훨씬 쉽게 읽을 수 있습니다.

MVVM 패턴을 사용할 때 코드 뒤에 쓰는 것을 선호하지는 않지만, 그 코드가 순전히 UI와 관련된 것이라면 괜찮다고 생각합니다.

그러나 여기에서는 그렇지 않습니다. 코드 뒤에서 view-model 명령을 호출하는 것이므로 단순히 UI 관련이 아니며 view와 view-model 명령 간의 관계는 XAML에서 직접적으로 나타나지 않습니다.

첨부된 명령어 동작을 사용하면 XAML에서 쉽게 할 수 있을 것 같습니다.그렇게 하면 당신은 "결합"할 수 있습니다.MouseDoubleClick 뷰 에 대한 :

<ListView ItemSource="{Binding Items}">
   <local:CommandBehaviorCollection.Behaviors>
      <local:BehaviorBinding Event="MouseDoubleClick" Action="{Binding DoSomething}" />
   </local:CommandBehaviorCollection.Behaviors>

    ...
</ListView>

또한선항쉽목수액있다습니의 접근할 수 .ListView 언지급하않고, 하여용사를 합니다.ICollectionView 인터페이스:

private ICommand _doSomething;

public ICommand DoSomething
{
    get
    {
        if (_doSomething == null)
        {
            _doSomething = new DelegateCommand(
                () =>
                {
                    ICollectionView view = CollectionViewSource.GetDefaultView(Items);
                    object selected = view.CurrentItem;
                    DoSomethingWithItem(selected);
                });
        }
        return _doSomething;
    }
}

저는 "코드 이면에 코드가 없다"는 목표가 바로 그것, 도달해야 할 목표라고 믿습니다. 절대적인 독단으로 받아들여야 하는 것이 아닙니다.보기에는 코드에 대한 적절한 위치가 있습니다. 이는 코드가 대체 접근 방식보다 단순한 위치 또는 방법에 대한 나쁜 예가 아닙니다.

연결된 속성 또는 연결된 이벤트를 포함하여 나열하는 다른 접근 방식의 장점은 재사용할 수 있다는 것입니다.이벤트를 직접 연결한 후 수행한 작업을 수행하면 응용 프로그램 전체에서 해당 코드를 복제하기가 매우 쉽습니다.해당 배선을 처리하기 위해 연결된 단일 속성 또는 이벤트를 만들면 배관에 코드를 추가할 수 있지만, 이 코드는 더블 클릭 처리를 원하는 ListView에 재사용할 수 있습니다.

그렇긴 하지만, 저는 더 "순수주의적인" 접근법을 선호하는 경향이 있습니다.모든 이벤트 처리를 보기에서 제외하는 것은 테스트 시나리오(특히 사용자가 다루는)에 영향을 미치지 않을 수 있지만 전체적인 설계 가능성과 유지 관리 가능성에는 영향을 미칩니다.코드 뒤에 코드를 삽입하면 이벤트 핸들러가 연결된 상태에서 항상 목록 보기를 사용하도록 보기를 제한할 수 있습니다. 이 경우 보기가 코드로 연결되고 디자이너가 유연하게 재설계할 수 없게 됩니다.

@JP가 원래 질문에서 설명하고 @Heinzi가 답변에서 언급하는 것은 어려운 명령을 처리하는 실용적인 접근 방식입니다.명령을 호출하기 전에 약간의 UI 작업을 수행해야 할 때 뒤에 있는 코드에서 이벤트 처리 코드를 사용하는 것이 특히 유용합니다.

OpenFileDialog의 전형적인 예를 생각해 보십시오.MVVM 툴킷에서 사용하는 복잡한 메시징 루틴을 채택하는 것보다 버튼에서 클릭 이벤트를 사용하고 대화 상자를 표시한 다음 결과를 View Model의 명령으로 보내는 것이 훨씬 쉽습니다.

XAML에서:

<Button DockPanel.Dock="Left" Click="AttachFilesClicked">Attach files</Button>

당신의 코드 뒤에:

    private void AttachFilesClicked(object sender, System.Windows.RoutedEventArgs e)
    {
        // Configure open file dialog box
        Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
        dlg.FileName = "Document"; // Default file name
        dlg.DefaultExt = ".txt"; // Default file extension
        dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension

        // Show open file dialog box
        bool? result = dlg.ShowDialog();

        // Process open file dialog box results
        if (result == true)
        {
            string filename = dlg.FileName;

            // Invoke the command.
            MyViewModel myViewModel = (MyViewModel)DataContext;
            if (myViewModel .AttachFilesCommand.CanExecute(filename))
            {
                noteViewModel.AttachFilesCommand.Execute(filename);  
            }
        }
    }

컴퓨터 프로그래밍은 융통성이 없습니다.우리 프로그래머들은 그것을 다루기 위해서는 융통성이 있어야 합니다.

디커플링은 MVVM의 주요 기능 중 하나입니다.뷰 또는 바인딩된 모델을 변경하려는 경우 뷰 또는 바인딩된 모델이라고 가정합니다.당신의 지원은 얼마나 쉽습니까?

View1과 View2가 모두 동일한 View Model을 공유하는 예를 보겠습니다.이제 두 가지 모두에 대한 코드 이면의 방법을 구현해 보겠습니다.

또한 나중에 보기를 위해 보기 모델을 변경해야 하는 경우 보기 모델이 변경되고 문이 지정되면 명령이 실패한다고 가정합니다.

MyViewModel vm = this.DataContext as MyViewModel;

null을 반환하므로 코드가 충돌합니다.따라서 뒤에 있는 코드를 변경해야 하는 추가 부담이 있습니다.이런 식으로 하면 이런 시나리오가 발생합니다.

물론 프로그래밍에서 동일한 것을 달성하는 방법은 여러 가지가 있지만 어느 것이 최선인지가 최선의 접근으로 이어질 것입니다.

명령은 침팬지를 위한 것입니다.진짜 남자들은 그들의 모든 UI를 코드 뒤에 있는 이벤트에 연결합니다.

언급URL : https://stackoverflow.com/questions/2087743/mvvm-madness-commands

반응형