2017-07-18 43 views
0

我一直在做一个小样本Wpf Mvvm项目,用于试验INotifyPropertyChanged接口。该项目实际上正常工作,但我遇到的问题是,只有在MainWindow.xaml后面的代码中设置DataContext时,项目才能正常工作。如果我尝试在xaml标记中设置DataContext,那么该项目的某些功能不起作用。用户界面包含一个文本块,文本框(用于输入要显示在文本块OnPropertyChanged中的文本)和提交按钮(除了提供从文本框中丢失焦点的地方,它实际上什么也不做)以及3个用于改变背景颜色的其他按钮(颜色按钮) UI。 UI的默认颜色是橙色 - 直到通过单击任何颜色按钮更改颜色为止为什么我的WPF项目中的datacontext从后台代码正确运行,但不能从xaml运行?

有3个viewModels,PersonViewModel(文本框绑定到),BackgroundViewModel(用于颜色按钮)和一个MainViewModel它结合了另外两个viewModels。 viewModels驻留在项目的viewModels文件夹中。还有一个实现INotifyPropertyChanged接口并由PersonViewModel和BackgroundViewModel继承的ObservableObject类(基本上是ViewModelBase类)。 ObservableObject.cs驻留在项目的根文件夹中。

该项目不是纯粹的Mvvm。颜色按钮在MainWindow.xaml后面的代码中使用click事件。如果我在MainWindow.xaml后面的代码中设置了DataContext,那么一切正常。如果我在xaml标记中设置DataContext - 文本框/文本块功能可以工作,但颜色按钮不会更改UI的背景颜色。当我遍历代码时,它会正确运行所有代码,但UI背景颜色不会更改。我猜这是一件有约束力的事情。

示例项目可以下载here

的代码如下。如果我在xaml标记中设置DataContext,我怎样才能使这个项目的功能正确?我尝试了以下将在其上设置了用户界面的默认橙色网格绑定,但颜色按钮不起作用:

<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

with''你有** 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> 

,并在后面的代码,你会从设置_main由铸造的DataContext到MainViewModel

MainViewModel _main; 

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

另外,取出的DataContext XAML,并使用此MainWindow构造函数:

private readonly MainViewModel _main = new MainViewModel(); 

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

我稍微更新了答案。如果在XAML中设置DataContext,则不需要在后面的代码中新建MainViewModel。 – Marc

1

当你从XAML绑定您的视图模型它不能工作,因为在你的代码后面,你将颜色设置为你本地的ViewModel“_main”。但是,_main并不局限于View,bc是。

+0

我想我的问题是这样的 - 有没有办法将_main绑定到当前设置中的视图?或者代码是这种设置的唯一方式? –

+0

尝试Marc已经回答的问题。 – Ben

相关问题