2016-05-03 12 views
0

Hoffe jemand kann mich auf die besten mvvm Praxis mit Service-Locator aufklären. Grundprinzipien sind klar. Ich habe meine Ansichten mit entsprechenden Ansichtsmodellen, an denen alles arbeiten soll.SimpleIoc MVVM Auflösung Ansicht (UserControl)

Lassen Sie uns ein einfaches Beispiel machen. Ich habe ein Hauptfenster und 2 Benutzer steuert UCA und UCB. Jeder von ihnen hat ein in der Locator-Klasse registriertes View-Modell.

Mit diesem IoC-Muster, wie können Sie UCA und UCB im Hauptfenster mit einer Inhaltskontrolle und Bindung durch Hauptfensteransichtsmodell anzeigen? Um genau zu sein, möchte ich nur ein Steuerelement gleichzeitig zeigen. Ich kann das UCA- oder UCB-Ansichtsmodell nicht binden, da dies View-First-Approach ist und die Ansicht nicht automatisch aufgelöst wird.

Was ist der richtige Ansatz dafür?

Dank

Antwort

0

Sie können einen separaten Dienst für den Start Ansichten als Dialog erstellen, so dass es in allgemeiner Weise über die Anwendung verwendet werden kann. Und wird diesen Dienst über Constructor, der jeden Dialog starten will, in die ViewModel einfügen.

public interface IDialogService<T> 
{ 
    void Show(); 
    void ShowDialog(); 
} 

public class DialogService<T> : IDialogService<T> where T : Window 
{ 
    public void Show() 
    { 
     container.Resolve<T>().Show(); 
    } 

    public void ShowDialog() 
    { 
     container.Resolve<T>().ShowDialog(); 
    } 
} 

Jetzt injizieren Sie einfach diesen Dienst an die entsprechenden viewmodel.

public class YourViewModel 
{ 
    //commands 
    public ICommand someCommand { get; set; } 

    private IDialogService<BookingView> _dialogService; 
    public YourViewModel(IDialogService<YourView > dialogService) 
    { 
     _dialogService = dialogService 
     someCommand = new RelayCommand(someCommandDoJob,() => true); 
    } 

    public void someCommandDoJob(object obj) 
    { 
     //Since you want to launch this view as dialog you can set its datacontext in its own constructor.  
     _dialogService.ShowDialog(); 
    } 
} 
0

Eine Lösung könnte mit DataTrigger mit ContentTemplate Eigenschaft zusammen selektiv zu zeigen, UCA oder UCB (siehe Beispiel unten). UCA könnte auch als Standardansicht in einem Formatvorlagensatz festgelegt werden. In diesem Fall wird nur eine DataTriggers benötigt. Eine andere Lösung könnte die ContentTemplateSelector Eigenschaft verwenden und eine DataTemplateSelector implementieren.

See: ContentControl.ContentTemplateSelector (MSDN)

<!--content control in main window--> 
<ContentControl> 
    <ContentControl.Style> 
     <Style TargetType="ContentControl"> 
      <Style.Triggers> 
       <!--suppose main window view model has a bool property UseUCA--> 
       <!--if UseUCA is true render UCA view--> 
       <DataTrigger Binding="{Binding UseUCA}" Value="True"> 
        <DataTrigger.Setters> 
         <!--by setting ContentTemplate property you control what is rendered inside of the content control--> 
         <Setter Property="ContentTemplate"> 
          <Setter.Value> 
           <DataTemplate> 
            <!--render UCA view--> 
            <local:UCA /> 
           </DataTemplate> 
          </Setter.Value> 
         </Setter> 
        </DataTrigger.Setters> 
       </DataTrigger> 
       <!--if UseUCA is false render UCB view--> 
       <DataTrigger Binding="{Binding UseUCA}" Value="False"> 
        <DataTrigger.Setters> 
         <Setter Property="ContentTemplate"> 
          <Setter.Value> 
           <DataTemplate> 
            <!--render UCB view--> 
            <local:UCB /> 
           </DataTemplate> 
          </Setter.Value> 
         </Setter> 
        </DataTrigger.Setters> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </ContentControl.Style> 
</ContentControl> 
0

OK ... hier ist ein Gedanke ... können Sie den Überblick über die „Current“ in Ihrem MainViewModel halten und lassen Sie die UI die korrekte Steuerung zeigen auf Typ. Hier ist ein kurzes Beispiel. Ich benutze einen Knopf, um Ansichten zu wechseln ... dies könnte idealerweise über jede Logik erfolgen, die Ihren Anforderungen entspricht.

Mainwindow:

<Window x:Class="WpfApplication4.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfApplication4" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525" 
     DataContext="{Binding Main, Source={StaticResource Locator}}"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="30" /> 
      <RowDefinition Height="*" /> 
     </Grid.RowDefinitions> 
     <Button Content="Switch Views" Command="{Binding SwitchViewsCommand}" /> 
     <ContentControl Grid.Row="1" Content="{Binding CurrentControl}"> 

     </ContentControl> 
    </Grid> 
</Window> 

UCA und UCB sind einfach Benutzerkontrollen mit unterschiedlichem Text in ihnen:

<UserControl x:Class="WpfApplication4.UserControls.UCA" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:WpfApplication4.UserControls" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <TextBlock Text="This is user control A" /> 
    </Grid> 
</UserControl> 

UCAViewModel und UCBViewModel sind leer Viewmodel in meinem Beispiel, die von ViewModelBase erbt

namespace WpfApplication4.ViewModel 
{ 
    public class UCAViewModel : ViewModelBase 
    { 
    } 
} 

Das MainViewModel behandelt die aktuell angezeigte Ansicht basierend auf seinem Ansichtsmodell

using GalaSoft.MvvmLight; 
using GalaSoft.MvvmLight.Command; 
using Microsoft.Practices.ServiceLocation; 

namespace WpfApplication4.ViewModel 
{ 
    public class MainViewModel : ViewModelBase 
    { 
     public MainViewModel() 
     { 
      RegisterCommands(); 
      SwitchView(); 
     } 

     private void SwitchView() 
     { 
      if(CurrentControl == null) 
      { 
       CurrentControl = ServiceLocator.Current.GetInstance<UCAViewModel>(); 
      } 
      else 
      { 
       if(CurrentControl is UCAViewModel) 
        CurrentControl = ServiceLocator.Current.GetInstance<UCBViewModel>(); 
       else 
        CurrentControl = ServiceLocator.Current.GetInstance<UCAViewModel>(); 


      } 
     } 

     private ViewModelBase _currentControl; 
     public ViewModelBase CurrentControl 
     { 
      get { return _currentControl; } 
      set 
      { 
       if (_currentControl != value) 
       { 
        _currentControl = value; 
        RaisePropertyChanged("CurrentControl"); 
       } 
      } 
     } 

     private void RegisterCommands() 
     { 
      SwitchViewsCommand = new RelayCommand(SwitchView); 
     } 

     public RelayCommand SwitchViewsCommand { get; private set; } 
    } 
} 

der ViewModelLocator speichert die Instanzen

using GalaSoft.MvvmLight; 
using GalaSoft.MvvmLight.Ioc; 
using Microsoft.Practices.ServiceLocation; 

namespace WpfApplication4.ViewModel 
{ 
    /// <summary> 
    /// This class contains static references to all the view models in the 
    /// application and provides an entry point for the bindings. 
    /// </summary> 
    public class ViewModelLocator 
    { 
     /// <summary> 
     /// Initializes a new instance of the ViewModelLocator class. 
     /// </summary> 
     public ViewModelLocator() 
     { 
      ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); 

      SimpleIoc.Default.Register<MainViewModel>(); 
      SimpleIoc.Default.Register<UCAViewModel>(); 
      SimpleIoc.Default.Register<UCBViewModel>(); 
     } 

     public MainViewModel Main 
     { 
      get 
      { 
       return ServiceLocator.Current.GetInstance<MainViewModel>(); 
      } 
     } 

     public static void Cleanup() 
     { 
      // TODO Clear the ViewModels 
     } 
    } 
} 

Und schließlich der Klebstoff, der die richtige Ansicht Show macht, wird in der App getan.Xaml-Datei:

<Application x:Class="WpfApplication4.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication4" StartupUri="MainWindow.xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d1p1:Ignorable="d" xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:localUC="clr-namespace:WpfApplication4.UserControls" 
      xmlns:vm="clr-namespace:WpfApplication4.ViewModel"> 
    <Application.Resources> 
     <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" /> 
     <DataTemplate DataType="{x:Type vm:UCAViewModel}"> 
      <localUC:UCA /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type vm:UCBViewModel}"> 
      <localUC:UCB /> 
     </DataTemplate> 
    </Application.Resources> 
</Application> 
Verwandte Themen