2012-06-12 1 views
6

私は現時点でWPFとMVVMを学習しています(または少なくとも私は...しようとしています)。Buttonclickのビューを変更する

私は2つのボタンを持つウィンドウを表示する小さなsample-appを作成しました。それぞれには、クリック時の新しいビューが表示されます。そこで私は3つのUserControls(2つのボタンを持つDecisonMakerと、各 "clicktarget"のための1つのUsercontrol)を作成しました。

だから、私はMainWindowViewModelで "CurrentView" と呼ばれるプロパティMainWindow.xamlの

コードにメインウィンドウのCotentControlをバインド:MainWindowViewModelの

<Window x:Class="WpfTestApplication.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfTestApplication" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.DataContext> 
    <local:MainWindowViewModel /> 
</Window.DataContext> 
<Grid> 
    <ContentControl Content="{Binding CurrentView, Mode=OneWay}" /> 
</Grid> 
</Window> 

コード:

class MainWindowViewModel 
{  
    private UserControl _currentView = new DecisionMaker(); 
    public UserControl CurrentView 
    { 
     get { return _currentView; } 
     set { _currentView = value; } 
    } 

    public ICommand MausCommand 
    { 
     get { return new RelayCommand(LoadMouseView); } 
    } 

    public ICommand TouchCommand 
    { 
     get { return new RelayCommand(LoadTouchView); } 
    } 

    private void LoadMouseView() 
    { 
     CurrentView = new UserControlMouse(); 
    } 

    private void LoadTouchView() 
    { 
     CurrentView = new UserControlTouch(); 
    } 
} 

最初のUserControl(DecisionMaker)が想定どおりに表示されます。また、メソッドLoadMouseViewが呼び出されます。しかし、ビューは変更されません。私は何が欠けていますか?

更新日:ありがとうございます!私はINotifyPropertyChangedインターフェイスを見逃しました。すべてのあなたの答えは素晴らしく、非常に正確で有用でした!私はどちらを受け入れるか分からない - "最初の"答えを受け入れることが最も公正な方法だと思いますか?

私は問題を解決し、MVVMをよりよく理解するのを助けてくれたので、盲目的な答えを受け入れました。しかし、すべての答えは皆さんのおかげで本当に素晴らしかったです!

+1

ビューモデルビュー/ユーザーコントロールへの参照を持つべきではありません。あなたのビューモデルからこれを削除する必要があります。これは良い出発点です:http://msdn.microsoft.com/en-us/magazine/dd419663.aspx – blindmeis

答えて

6

もしmvvmをしたいのであれば、は参照番号あなたのviewmodelにあなたのビュー/ usercontrolsを持っているはずです。あなたは実装する必要がありますINotifyPropertyChanged! ps:あなたのViewModelにSystem.Windows名前空間が必要な場合 - 何かが間違っています。

何が必要あなたの場合:UserControlMouse

  • 1 UserControlMouse
  • 1のためのビュー/ユーザーコントロールのためのUserControlTouch
  • 1ビュー/ユーザーコントロールのためのviewmodelため

    • 1 mainviewmodel
    • 1のviewmodel UserControlTouch

    mainviewmodelには、ビューを切り替えるために少なくとも2つのコマンドがあり、CurrentViewには1つのプロパティが必要です。あなたのコマンドでは、CurrentViewを正しいviewmodelインスタンスに設定するだけです。少なくとも、適切なビューを定義する各ビューモデルに対して2つのデータ・テンプレートが必要です。

    public object CurrentView 
    { 
        get { return _currentView; } 
        set { 
         _currentView = value; this.RaiseNotifyPropertyChanged("CurrentView");} 
    } 
    

    XAML

    <Window x:Class="WpfTestApplication.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfTestApplication" 
    Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
    <DataTemplate DataType="{x:Type local:MyMouseViewModel}"> 
        <local:MyMouseUserControlView/> 
        </DataTemplate> 
    <DataTemplate DataType="{x:Type local:MyTouchViewModel}"> 
        <local:MyTouchUserControlView/> 
        </DataTemplate> 
    </Window.Resources> 
    <Window.DataContext> 
    <local:MainWindowViewModel /> 
    </Window.DataContext> 
    <Grid> 
    
    <!-- here your buttons with command binding, i'm too lazy to write this. --> 
    
    <!-- you content control --> 
    <ContentControl Content="{Binding CurrentView, Mode=OneWay}" /> 
    </Grid> 
    </Window> 
    
  • +0

    これは私の学習進歩のための多くの助けと情報です。私はちょうどWPF/MVVMで昨日始めたので、ICommand-Behaviorを動作させるのはむしろ幸せでした;) – basti

    +0

    純粋なMVVMが必要な場合は、ビューにビューモデルへの参照があってはなりません。アプリケーションの起動時にビューとモデルをインスタンス化し、スタートアップメソッドのデータコンテキストにビューモデルをバインドします。 –

    +0

    +1 "あなたのViewModelにSystem.Windows名前空間が必要な場合 - 何かが間違っています。"私はそれに強く同意する。残念ながら、多くのMVVMの記事とフレームワークでは、ViewModelのWPFアセンブリから不要な依存関係が導入された「ICommand」からコマンドを派生することを推奨しています。 –

    2

    viewmodelはINotifyPropertyChangedを実装する必要があります。そうしないと、ビューモデル内でプロパティが変更されたときにビューに通知されません。

    class MainWindowViewModel : INotifyPropertyChanged 
    { 
        private UserControl _currentView = new DecisionMaker(); 
    
        public UserControl CurrentView 
        { 
         get { return _currentView; } 
         set 
         { 
          _currentView = value; 
          OnPropertyChanged("CurrentView"); 
         } 
        } 
    
        public event PropertyChangedEventHandler PropertyChanged; 
        private void OnPropertyChanged(string propertyName) 
        { 
         if (PropertyChanged != null) 
         { 
          PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
         } 
        } 
    } 
    
    +0

    ありがとう私はこれを既に実装した(あなたの答えの後)とそれは正常に動作します。しかし、なぜString型のプロパティではなく、ここでそれが必要なのでしょうか? – basti

    +1

    これはあなたのケースでは機能しますが、それはmvvmではありません – blindmeis

    1

    あなたはCurrentViewプロパティが変更されたときにビューが通知されるように、MainWindowViewModelINotifyPropertyChangedを実装する必要があります。

    3

    私は入力スタイルを選択するために、MainWindowにこれを行います。入力モードを選択できるプロパティを追加しました。

    public enum UserInterfaceModes 
    { 
        Mouse, 
        Touch, 
    } 
    
    public UserInterfaceModes UserInterfaceMode 
    { 
        get { return (UserInterfaceModes)GetValue(UserInterfaceModeProperty); } 
        set { SetValue(UserInterfaceModeProperty, value); } 
    } 
    
    public static readonly DependencyProperty UserInterfaceModeProperty = DependencyProperty.Register("UserInterfaceMode", typeof(UserInterfaceModes), typeof(MainWindow), new UIPropertyMetadata(UserInterfaceModes.Mouse)); 
    

    xamlビューの部分では、トリガーで正しいテンプレートを選択できます。これはコントロールに組み込まれて使用し、ちょうど同じビューモデルに両方のタブのDataContextを結合しない理由 - それはあなたが望む行動のように聞こえる

    <Style TargetType="{x:Type local:MainWindow}"> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding UserInterfaceMode}" Value="Mouse"> 
          <Setter Property="Template"> 
            <Setter.Value> 
             <ControlTemplate TargetType="{x:Type local:MainWindow}"> 
              <Grid Background="Red"/> 
             </ControlTemplate> 
            </Setter.Value> 
          </Setter> 
         </DataTrigger> 
         <DataTrigger Binding="{Binding UserInterfaceMode}" Value="Touch"> 
          <Setter Property="Template"> 
            <Setter.Value> 
             <ControlTemplate TargetType="{x:Type local:MainWindow}"> 
              <Grid Background="Blue"/> 
             </ControlTemplate> 
            </Setter.Value> 
           </Setter> 
         </DataTrigger> 
        </Style.Triggers> 
    </Style> 
    
    +0

    確かに素晴らしい答えです。この特定の問題については、今テスト/ラーニングに直面していますが、これはボタンレイアウト全体を無効にするため100%適用されません) 今後の「実際の」実装では、必ずコードに戻ってきます! – basti

    +0

    Aww、あなたは私を赤面させるでしょう! :D – Andy

    1

    はかなりあなたが[TabControl][1]で得るものです。

    これはまた、ビューモデルがビュークラスについてわからないという利点があります(私はUserControlMouseなどがユーザーコントロールであると仮定しています)。

    注:ビューモデルがタッチモードかマウスモードかを認識する必要がある場合は、これは適用されません。

    +0

    ありがとうございます。それはMouse-and TouchModeのUserControlを分割するための全体的なターゲットです。ですから、スタートタイムでは、私はstart-usercontrolsを "知る"必要があります。 – basti

    +0

    @chiffre MVVMを実行する場合は、ビューモデルでビューコンポーネント(ユーザーコントロール)を参照してはいけません –

    +0

    私は将来の作業のためにblindmeisの答えに従うと思います。この場合、あなたの大きな助けに感謝します! – basti

    関連する問題