2016-05-03 12 views
0

誰かがサービスロケータを使用して最高のMVVの練習で私を啓発できることを願っています。 基本原則は明確です。私は対応するビューモデルで私の意見を持って、すべてがそれで動作します。SimpleIoc MVVM解決ビュー(UserControl)

簡単な例を示します。私は1つのメインウィンドウと2つのユーザーコントロールUCAとUCBを持っています。それぞれにはロケータクラスに登録されたビューモデルがあります。

このIoCパターンを使用すると、1つのコンテンツコントロールとメインウィンドウビューモデルによるバインディングを使用して、メインウィンドウにUCAとUCBをどのように表示できますか?正確には、同時に1つのコントロールだけを表示したいのです。これはビューの最初のアプローチなので、UCAまたはUCBビューモデルをバインドできません。ビューは自動的に解決されません。

これには正しい方法はありますか?

おかげ

答えて

0

それはアプリケーション間で一般的な方法で使用することができるようにあなたは、ダイアログとしてビューを起動するための独立したサービスを作成することができます。そして、ダイアログを起動したいConstructor経由でこのサービスをViewModelに注入します。

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(); 
    } 
} 

このサービスをそれぞれ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

一つの解決策は、選択的UCAまたはUCB(以下の例を参照)を表示するDataTriggerと共にContentTemplateプロパティを使用することができます。 UCAは、スタイル設定ツールでデフォルトビューとして設定することもできます。この場合は、DataTriggersが1つだけ必要です。

もう1つの解決策は、ContentTemplateSelectorプロパティを使用し、DataTemplateSelectorを実装することです。

参照: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 ...ここで考えている...あなたはあなたのMainViewModelに「currentview」を追跡し、UIは、タイプに基づいて、正しいコントロールを表示させることができます。ここに簡単な例があります。私はビューを切り替えるためにボタンを使用しています...これは理想的にあなたの要件に合う任意のロジックを介して行うことができます。

メインウィンドウ:

<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とUCBは、単にそれらの異なるテキストを持つユーザーコントロールです:

<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とUCBViewModelはViewModelBase

namespace WpfApplication4.ViewModel 
{ 
    public class UCAViewModel : ViewModelBase 
    { 
    } 
} 
から継承私の例では、空のviewmodelsです

MainViewModelは、現在表示されているビューを処理します。そののviewmodelに基づい

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; } 
    } 
} 

ViewModelLocatorはインスタンス

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 
     } 
    } 
} 

そして最後に、正しいビューショーを作る接着剤がアプリで行われているが保存されます。xamlファイル:

<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> 
関連する問題