C# 为什么我的WPF项目中的datacontext可以从代码隐藏而不是xaml正常工作?
我一直在做一个小样本Wpf Mvvm项目,用于试验INotifyPropertyChanged接口。该项目实际上工作正常,但我遇到的问题是,只有在MainWindow.xaml的代码隐藏中设置DataContext,该项目才能正常工作。如果我试图在xaml标记中设置DataContext,那么项目的一些功能就不起作用。UI包含一个textblock、textbox(用于输入要在textblock OnPropertyChanged中显示的文本)和submit按钮(除了提供一个使textbox失去焦点的位置外,它实际上什么都不做)以及3个用于更改UI背景色的其他按钮(颜色按钮)。UI的默认颜色为橙色——直到通过单击任何颜色按钮更改颜色为止 有3个视图模型,PersonViewModel(文本框绑定到它)、BackgroundViewModel(用于颜色按钮)和一个MainViewModel,它结合了其他两个视图模型。viewModels位于项目的viewModels文件夹中。还有一个ObserveObject类(基本上是ViewModelBase类),它实现INotifyPropertyChanged接口,并由PersonViewModel和BackgroundViewModel继承。ObservableObject.cs位于项目的根文件夹中 这个项目不是纯粹的Mvvm。颜色按钮在MainWindow.xaml的代码隐藏中使用单击事件。如果我在MainWindow.xaml的代码隐藏中设置了DataContext,那么一切都正常工作。如果我在xaml标记中设置DataContext——textbox/textblock功能可以工作,但是颜色按钮不会改变UI的背景色。当我一步一步地浏览代码时,它会正确地浏览所有代码,但UI背景颜色不会改变。我猜这是一个有约束力的东西 可以下载示例项目 代码如下。如果我在xaml标记中设置DataContext,如何使该项目正常运行?我在网格上尝试了以下绑定,它将为UI设置默认的橙色,但颜色按钮不起作用:C# 为什么我的WPF项目中的datacontext可以从代码隐藏而不是xaml正常工作?,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我一直在做一个小样本Wpf Mvvm项目,用于试验INotifyPropertyChanged接口。该项目实际上工作正常,但我遇到的问题是,只有在MainWindow.xaml的代码隐藏中设置DataContext,该项目才能正常工作。如果我试图在xaml标记中设置DataContext,那么项目的一些功能就不起作用。UI包含一个textblock、textbox(用于输入要在textblock OnPropertyChanged中显示的文本)和submit按钮(除了提供一个使textbox失去
<Grid Background="{Binding Background.Color}" DataContext="{StaticResource bc}">
--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");
}
}
}
}
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");
}
}
}
}
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;
}
}
}
--BackgroundViewModel.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");
}
}
}
}
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");
}
}
}
}
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;
}
}
}
--MainViewModel.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");
}
}
}
}
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");
}
}
}
}
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;
}
}
}
当您从XAML绑定ViewModel时,它无法工作,因为在后面的代码中,您正在为本地ViewModel“\u main”设置颜色。但是_main没有绑定到视图,bc是。当您从XAML绑定ViewModel时,它无法工作,因为在后面的代码中,您正在为本地ViewModel“_main”设置颜色。但是_main没有绑定到视图,bc是。您的后台代码使用的是_main对象,因此如果您想在XAML中设置DataContext,只需要使用DataContext设置_main即可 因此,在XAML中,您将
<Window.DataContext>
<VM:MainViewModel />
</Window.DataContext>
或者,从XAML中删除DataContext,并使用此主窗口构造函数:
private readonly MainViewModel _main = new MainViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _main;
}
您的代码隐藏正在使用_main对象,因此如果您想在XAML中设置DataContext,只需使用DataContext设置_main即可 因此,在XAML中,您将
<Window.DataContext>
<VM:MainViewModel />
</Window.DataContext>
或者,从XAML中删除DataContext,并使用此主窗口构造函数:
private readonly MainViewModel _main = new MainViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _main;
}
使用
可以创建2个MainViewModel对象。当前,即使您将“bc”设置为DataContext,按钮始终与在代码隐藏中创建的按钮一起工作。请参见此处:。虽然问题听起来完全不同,但我即将以重复的方式结束此操作。如果您真的想了解MVVM,您应该将这些单击事件从代码隐藏中移开,并将其转换为viewmodel上的ICommand
实现。我计划在此项目中使用ICommand作为MVVM中的练习。在继续下一个示例实现之前,我只想确保我没有遗漏对DataContext的任何理解。谢谢大家的回复。建议的stackoverflow.com/a/34617048/1136211链接有我想要的解决方案——我可以在xaml中设置datacontext,然后在代码中声明_main,如下所示--_main=(MainViewModel)datacontext;现在我的示例项目工作了!使用
可以创建2个MainViewModel对象。当前,即使您将“bc”设置为DataContext,按钮始终与在代码隐藏中创建的按钮一起工作。请参见此处:。虽然问题听起来完全不同,但我即将以重复的方式结束此操作。如果您真的想了解MVVM,您应该将这些单击事件从代码隐藏中移开,并将其转换为viewmodel上的ICommand
实现。我计划在此项目中使用ICommand作为MVVM中的练习。在继续下一个示例实现之前,我只想确保我没有遗漏对DataContext的任何理解。谢谢大家的回复。建议的stackoverflow.com/a/34617048/1136211链接有我想要的解决方案——我可以在xaml中设置datacontext,然后在代码中声明_main,如下所示--_main=(MainViewModel)datacontext;现在我的示例项目工作了!我想我的问题是——在我当前的设置中,有没有办法将main绑定到视图?或者代码隐藏是这个设置的唯一方法吗?试试Marc的回答。我想我的问题是——在我当前的设置中,有没有一种方法可以将_main绑定到视图?或者代码隐藏是这个设置的唯一方法吗?试试Marc的答案。我稍微更新了答案。如果在XAML中设置DataContext,则不需要在代码隐藏中更新MainViewModel。我稍微更新了答案。如果在XAML中设置DataContext,则不需要在代码隐藏中新建MainViewModel。