WPF MVVM Dlaczego warto używać widoków ContentControl + DataTemplate zamiast prostych widoków okien XAML?

83

Dlaczego to?

MainWindow.xaml:

<Window x:Class="MVVMProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <ContentControl Content="{Binding}"/>
    </Grid>
</Window>

Ustaw plik ExampleView.xaml jako:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vms="clr-namespace:MVVMProject.ViewModels">
    <DataTemplate DataType="{x:Type vms:ExampleVM}" >
        <Grid>
            <ActualContent/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

I utwórz okno w ten sposób:

public partial class App : Application {

    protected override void OnStartup(StartupEventArgs e) {

        base.OnStartup(e);

        MainWindow app = new MainWindow();
        ExampleVM context = new ExampleVM();
        app.DataContext = context;
        app.Show();
    }
}

Kiedy można to zrobić w ten sposób?

App.xaml: (Ustaw okno startowe / Widok)

<Application x:Class="MVVMProject.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="ExampleView.xaml">
</Application>

ExampleView.xaml: (okno, a nie ResourceDictionary)

<Window x:Class="MVVMProject.ExampleView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vms="clr-namespace:MVVMProject.ViewModels">
    >
    <Window.DataContext>
        <vms:ExampleVM />
    </Window.DataContext>

    <Grid>
        <ActualContent/>
    </Grid>
</Window>

Zasadniczo jest to „Wyświetl jako szablon danych” (VaD) a „Wyświetl jako okno” (VaW)

Oto moje rozumienie porównania:

  • VaD: Umożliwia przełączanie widoków bez zamykania okna. (Nie jest to pożądane w moim projekcie)
  • VaD: VM nie wie absolutnie nic o widoku, podczas gdy w VaW musi (tylko) mieć możliwość jego instancji podczas otwierania innego okna
  • VaW: Faktycznie widzę mój Xaml renderowany w Projektancie (nie mogę z VaD, przynajmniej w mojej obecnej konfiguracji)
  • VaW: działa intuicyjnie przy otwieraniu i zamykaniu okien; każde okno ma (jest) odpowiadający mu Widok (i ViewModel)
  • VaD: ViewModel może przechodzić wzdłuż początkowej szerokości okna, wysokości, możliwości zmiany rozmiaru itp. Poprzez właściwości (podczas gdy w VaW są one ustawiane bezpośrednio w oknie)
  • VaW: można ustawić FocusManager.FocusedElement (nie wiem jak w VaD)
  • VaW: Mniej plików, ponieważ moje typy okien (np. Wstążka, Okno dialogowe) są włączone do ich widoków

Więc co się tutaj dzieje? Czy nie mogę po prostu zbudować moich okien w XAML, uzyskać czysty dostęp do ich danych poprzez właściwości maszyny wirtualnej i skończyć z tym? Kod jest taki sam (praktycznie zerowy).

Usiłuję zrozumieć, dlaczego powinienem przetasować wszystkie elementy widoku do ResourceDictionary.

Simon F.
źródło
2
Pomyśl w ten sposób: ViewModels powinny być wyświetlane w systemie Windows lub w UserControls. Poco będą wyświetlane w DataTemplates. :)
dev hedgehog

Odpowiedzi:

130

Ludzie używają DataTemplatestego sposobu, gdy chcą dynamicznie przełączać widoki w zależności od ViewModel:

<Window>
    <Window.Resources>
       <DataTemplate DataType="{x:Type local:VM1}">
          <!-- View 1 Here -->
       </DataTemplate>

       <DataTemplate DataType="{x:Type local:VM2}">
          <!-- View 2 here -->
       </DataTemplate>
    </Window.Resources>

    <ContentPresenter Content="{Binding}"/>

</Window>

Więc,

jeśli Window.DataContextjest instancją VM1, to View1zostanie wyświetlone,

i jeśli

Window.DataContextjest instancją VM2, a następnie View2zostanie wyświetlony.

To prawda, nie ma to żadnego sensu, jeśli oczekiwany jest tylko 1 widok i nigdy się nie zmienia.

Federico Berasategui
źródło
8

Ponieważ w VaD modele widoków nie wiedzą nic o widokach, można zbudować w pełni funkcjonalną aplikację składającą się wyłącznie z modeli widoków bez widoków. Prowadzi to do możliwości napisania aplikacji, która może być sterowana w całości przez kod. To z kolei prowadzi do możliwości wykonania testów integracyjnych bez GUI. Testowanie integracji przez GUI jest notorycznie delikatne - podczas gdy testowanie za pomocą modeli widoku powinno być bardziej niezawodne.

Phillip Ngan
źródło
5

Z mojego osobistego doświadczenia: oba modele pracy są dostępne, w zależności od tego, czego chcesz i w zależności od wymagań aplikacji. Ideą VaDjest usunięcie zawartości i pojemnika. Jeśli zaimplementujesz VaD, możesz użyć tego szablonu (domyślnie), gdy pokażesz jakikolwiek element tego typu. Możesz go używać w ItemsControls(listach, widokach list, siatkach itp.) I ContentControlstylko podczas tworzenia powiązań. Jak powiedziałeś, VaDdziała w celu przełączania zawartości okna bez zamykania i otwierania nowego. Możesz również zdefiniować widok za pomocą UserControls, a następnie przejąć kontrolę nad elementami, które są skupione, a także możesz zarządzać kodem za. Twój szablon danych może więc wyglądać następująco:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vms="clr-namespace:MVVMProject.ViewModels">
<DataTemplate DataType="{x:Type vms:ExampleVM}" >
    <CustomUserControl A="{Binding A}" B="{Binding B}" DataContext="{Binding}" .../>
</DataTemplate>

Możesz również UserControlustawić właściwości zależności, które ułatwiają zadanie, ponieważ zezwalają na powiązania i oddzielenie aplikacji.

Ale oczywiście, jeśli Twoja aplikacja nie wymaga dynamicznego przełączania treści, można jej użyć VaWw oknie głównym lub dowolnym innym oknie. W rzeczywistości możesz używać obu VaWi VaD. Ten ostatni może być używany do elementów wewnętrznych w aplikacji, które nie wymagają okien. Wybierasz, co jest dla Ciebie lepsze, w zależności od wymagań aplikacji i czasu dostępnego na jej opracowanie. Mam nadzieję, że to osobiste doświadczenie pomoże ...

Raúl Otaño
źródło