2017-07-18 3 views
0

私は、INotifyPropertyChangedインターフェースを実験するための小さなサンプルのWpf Mvvmプロジェクトに取り組んでいます。プロジェクトは実際に正しく動作しますが、問題はMainWindow.xamlのコードの後ろにDataContextを設定するとプロジェクトが正しく動作することです。 xamlマークアップでDataContextを設定しようとすると、プロジェクトの機能のいくつかが機能しません。 UIにはテキストブロック、テキストボックス(テキストブロックOnPropertyChangedで表示するテキストを入力するため)、送信ボタン(テキストボックスからフォーカスを失う場所を提供する以外は何もしません)、背景色を変更するための3つのボタンUI。 UIのデフォルトの色はオレンジです - 色のボタンをクリックすると色が変わるまでなぜ私のWPFプロジェクトのdatacontextはxamlのコードではなく正しく機能していますか?

3つのviewModel、PersonViewModel(テキストボックスがバインド)、BackgroundViewModel(カラーボタン用)、およびMainViewModel 2つの他のviewModelを結合します。 viewModelは、プロジェクトのviewModelsフォルダにあります。 INotifyPropertyChangedインタフェースを実装し、PersonViewModelとBackgroundViewModelによって継承されるObservableObjectクラス(基本的にViewModelBaseクラス)もあります。 ObservableObject.csはプロジェクトのルートフォルダにあります。

プロジェクトは純粋なMvvmではありません。カラーボタンは、MainWindow.xamlのコードの後ろにあるクリックイベントを使用します。 MainWindow.xamlのコードビハインドにDataContextを設定すると、すべて正常に動作します。 DataContextをxamlマークアップに設定すると、textbox/textblock機能は機能しますが、カラーボタンはUIの背景色を変更しません。コードをステップ実行すると、すべてのコードが正しく実行されますが、UIの背景色は変更されません。私はそれが拘束力のあるものだと推測しています。

サンプルプロジェクトはhere

コードは以下の通りですが、ダウンロードすることができます。 xamlのマークアップにDataContextを設定すると、このプロジェクトが正しく機能するようにはできますか?私は、UIのデフォルトのオレンジ色を設定しますグリッド上で以下の結合を試みたが、色のボタンは動作しません:

<Grid Background="{Binding Background.Color}" DataContext="{StaticResource bc}"> 

--MainWindow.xaml

<Window x:Class="NotifyChangeExample.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:NotifyChangeExample" 
    xmlns:VM="clr-namespace:NotifyChangeExample.ViewModels" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="550" Width="525"> 

    <!--<Window.DataContext>   
     <VM:MainViewModel /> 
    </Window.DataContext>--> 

    <Window.Resources> 
     <VM:MainViewModel x:Key="bc" /> 
    </Window.Resources> 

    <Grid Background="{Binding Background.Color}" DataContext="{StaticResource bc}"> 
    <!--<Grid Background="{Binding Background.Color}">--> 
     <DockPanel LastChildFill="False" Margin="0,82,0,0"> 
      <StackPanel Width="150" DockPanel.Dock="Top"> 
       <TextBlock Text="{Binding Person.Name, StringFormat=Welcome (0)}" /> 
       <TextBox Text="{Binding Person.Name, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" /> 
       <Button>Submit</Button> 
      </StackPanel> 
      <StackPanel HorizontalAlignment="Center" Orientation="Horizontal" DockPanel.Dock="Bottom" > 
       <Button Click="Red_Clicked">Red Background</Button> 
       <Button Click="Blue_Clicked">Blue Background</Button> 
       <Button Click="Yellow_Clicked">Yellow Background</Button> 
      </StackPanel> 
     </DockPanel> 

    </Grid> 
</Window> 

--MainWindow .xaml.cs

using NotifyChangeExample.ViewModels; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace NotifyChangeExample 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     MainViewModel _main = new MainViewModel(); 

     public MainWindow() 
     { 
      InitializeComponent(); 
      //DataContext = _main; 
     } 

     private void Red_Clicked(object sender, RoutedEventArgs e) 
     { 
      _main.SetBackground(Brushes.Red); 
     } 

     private void Blue_Clicked(object sender, RoutedEventArgs e) 
     { 
      _main.SetBackground(Brushes.Blue); 
     } 

     private void Yellow_Clicked(object sender, RoutedEventArgs e) 
     { 
      _main.SetBackground(Brushes.Yellow); 
     } 
    } 
} 

--ObservableObject.cs

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace NotifyChangeExample 
{ 
    public class ObservableObject : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected void OnPropertyChanged(string name) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(name)); 
      } 
     } 
    } 
} 

--PersonViewModel.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace NotifyChangeExample.ViewModels 
{ 
    public class PersonViewModel : ObservableObject 
    { 
     private string _name; 

     public string Name 
     { 
      get 
      { 
       if (string.IsNullOrEmpty(_name)) 
        return "Unknown"; 
       return _name; 
      } 
      set 
      { 
       _name = value; 
       OnPropertyChanged("Name"); 
      } 
     } 
    } 
} 

--BackgroundViewModel.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Media; 

namespace NotifyChangeExample.ViewModels 
{ 
    public class BackgroundViewModel : ObservableObject 
    { 
     private Brush _color; 

     public Brush Color 
     { 
      get 
      { 
       if (_color == null) 
        return Brushes.Orange; 
       return _color; 
      } 
      set 
      { 
       _color = value; 
       OnPropertyChanged("Color"); 
      } 
     } 
    } 
} 

--MainViewModel.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Media; 

namespace NotifyChangeExample.ViewModels 
{ 
    public class MainViewModel 
    { 
     public PersonViewModel Person { get; private set; } 
     public BackgroundViewModel Background { get; private set; } 

     public MainViewModel() 
     { 
      Person = new PersonViewModel(); 
      Background = new BackgroundViewModel();  
     } 

     public void SetBackground(Brush brushColor) 
     { 
      Background.Color = brushColor; 
     } 
    } 
} 
+1

と ''は、** 2 ** MainViewModelオブジェクトを持っています。現在のボタンは、たとえ "bc"をDataContextとして設定していても、コードビハインドで作成されたボタンで常に機能します。 – ASh

+2

ここをクリックしてください:https://stackoverflow.com/a/34617048/1136211。私は疑問*が全く違うとは思うが、重複してこれを閉じようとしている。 – Clemens

+1

本当にMVVMに従いたいのであれば、そのクリックイベントをコードビハインドの外に移動し、それらをviewmodelの 'ICommand'実装に変換する必要があります。 –

答えて

1

コードビハインドは_mainオブジェクトを使用しているため、XAMLでDataContextを設定する場合は、DataContextを使用して_mainを設定する必要があります。

だから、XAMLで、あなたは

<Window.DataContext>   
    <VM:MainViewModel /> 
</Window.DataContext> 

とあなたの後ろにあなたのコード内からのDataContextを削除し、代わりにMainViewModel

MainViewModel _main; 

public MainWindow() 
{ 
    InitializeComponent(); 
    _main = (MainViewModel) DataContext; 
} 

へのDataContextをキャストすることによって_main設定します持っていますXAMLを作成し、このMainWindowコンストラクタを使用します。

private readonly MainViewModel _main = new MainViewModel(); 

public MainWindow() 
{ 
    InitializeComponent(); 
    DataContext = _main; 
} 
+0

私は少し答えを更新しました。 XAMLでDataContextを設定する場合は、コードの背後にあるMainViewModelを新規に作成する必要はありません。 – Marc

1

あなたはそれができないXAMLからあなたのViewModelにバインドされていますコードビハインドでは、ローカルViewModel "_main"に色を設定しているためです。しかし、_mainはViewにバインドされていません.BCはです。

+0

私の質問はこれだと思う - 私の現在の設定でビューに_mainをバインドする方法はありますか?または、このセットアップの唯一の方法の背後にあるコードですか? –

+0

マークが答えたことを試してみてください。 – Ben

関連する問題