MVVM 광기 : 명령
나는 MVVM을 좋아합니다. 나는 그것을 좋아하지 않지만 좋아합니다. 대부분 말이됩니다. 하지만 XAML을 작성할 수 있고 코드 숨김에 코드를 작성할 필요가 없도록 많은 코드를 작성하도록 권장하는 기사를 계속 읽고 있습니다.
예를 들어 보겠습니다.
최근에 ViewModel의 명령을 ListView MouseDoubleClickEvent에 연결하고 싶었습니다. 이 작업을 수행하는 방법을 잘 모르겠습니다. 다행히 Google은 모든 것에 대한 답을 가지고 있습니다. 다음 기사를 찾았습니다.
- http://blog.functionalfun.net/2008/09/hooking-up-commands-to-events-in-wpf.html
- http://joyfulwpf.blogspot.com/2009/05/mvvm-invoking-command-on-attached-event.html
- http://sachabarber.net/?p=514
- http://geekswithblogs.net/HouseOfBilz/archive/2009/08/27/adventures-in-mvvm-ndash-binding-commands-to-any-event.aspx
- http://marlongrech.wordpress.com/2008/12/13/attachedcommandbehavior-v2-aka-acb/
솔루션이 명령을 이해하는 데 도움이되었지만 문제가있었습니다. 앞서 언급 한 솔루션 중 일부는 종속성 속성 뒤에 "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 구현이 무엇인지에도 불구하고 이것이 문제에 대한 합리적인 해결책이라는 것을 보여주는 증명의 부담을 분명히 충족했다고 생각합니다.
(이 주장은 다중 패러다임 언어에 대한 주장과 유사하다고 생각합니다. 순수 OO 접근 방식을 적용 할 수 있지만 때로는 더 기능적인 방식으로 작업하는 것이 더 적절합니다. 순수 기능적 접근 방식을 적용 할 수 있지만 때로는 트레이드 오프가 OO를 보여줍니다. 기술은 그만한 가치가 있습니다.)
많은 MVVM-Command 솔루션이 너무 복잡하다는 데 동의합니다. 개인적으로 저는 혼합 된 접근 방식을 사용하고 ViewModel의 메서드와 속성을 사용하여 ViewModel이 아닌 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와 관련이있는 한 그렇게해도 괜찮다고 생각합니다.
그러나 여기에서는 그렇지 않습니다. 코드 숨김에서 뷰 모델 명령을 호출하므로 UI와 관련이없고 뷰와 뷰 모델 명령 간의 관계가 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;
}
}
I believe that the goal of having "No code in the code-behind" is exactly that, a goal to reach for - not something that you should take as an absolute dogma. There are appropriate places for code in the View - and this isn't necessarily a bad example of where or how code may be simpler than an alternative approach.
The advantage of the other approaches you list, including attached properties or attached events, is that they are reusable. When you hook up an event directly, then do what you did, it's very easy to end up duplicating that code throughout your application. By creating a single attached property or event to handle that wiring, you add some extra code in the plumbing - but it's code that is reusable for any ListView where you want double-click handling.
That being said, I tend to prefer using the more "purist" approach. Keeping all of the event handling out of the View may not effect the testing scenario (which you specifically address), but it does effect the overall designability and maintainability. By introducing code into your code behind, you're restricting your View to always using a ListView with the event handler wired - which does tie your View into code, and restrict the flexibility to redesign by a designer.
What @JP describes in the original question and @Heinzi mentions in is answer is a pragmatic approach to handling difficult commands. Using a tiny bit of event handling code in the code behind comes in especially handy when you need to do a little UI work before invoking the command.
Consider the classic case of the OpenFileDialog. It's much easier to use a click event on the button, display the dialog, and then send the results to a command on your ViewModel than to adopt any of the complicated messaging routines used by the MVVM toolkits.
In your XAML:
<Button DockPanel.Dock="Left" Click="AttachFilesClicked">Attach files</Button>
In your code behind:
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);
}
}
}
Computer programming is inflexible. We programmers have to be flexible to order to deal with that.
Decoupling is one of the major feature of MVVM. If suppose you want to change say view or binded model to it. How much easy it is for your application?
Take an example where View1 and View2 both share the same ViewModel. Now will you implement the code behind method for both.
Also, suppose if you need to change the viewmodel for a view on later stage your command will get fail as view model is changed and statement
MyViewModel vm = this.DataContext as MyViewModel;
will return null and hence code crash. So there comes an extra burden to change the code behind also. These kind of scenarios will arise if you do it in this way.
Of course there are many ways to achieve the same thing in programming but which one is best will lead to best approach.
Commanding is for chumps. Real men wire up their entire ui to events in codebehind.
참고URL : https://stackoverflow.com/questions/2087743/mvvm-madness-commands
'Nice programing' 카테고리의 다른 글
android Android 지원 리포지토리 대 Android 지원 라이브러리 대 Google 리포지토리 대 Google Play 서비스의 차이점은 무엇입니까? (0) | 2020.11.28 |
---|---|
docker-ce 및 docker-ee와 관련하여 docker.io는 무엇입니까? (0) | 2020.11.28 |
Spring 3 MVC 애플리케이션을위한 maven 2 archetype이 있습니까? (0) | 2020.11.28 |
여러 필드에 LINQ Distinct ()를 사용하는 방법 (0) | 2020.11.28 |
계산 된 열을 사용하여 동일한보기에서 다른 열을 계산하는 방법 (0) | 2020.11.28 |