在WPF中定义DataContext似乎有两种主要方式:
App.xaml.cs(取自WPF MVVM Toolkit template):
public partial class App : Application
{
private void OnStartup(object sender, StartupEventArgs e)
{
// Create the ViewModel and expose it using the View's DataContext
MainView mainView = new MainView();
MainViewModel mainViewModel = new MainViewModel();
mainViewModel.LoadCustomers("c:\\testdata2\\Customers.xml");
mainView.DataContext = mainViewModel;
mainView.Show();
}
}
Window1.xaml:
<DockPanel>
<StackPanel
HorizontalAlignment="Left"
DockPanel.Dock="Top"
Orientation="Horizontal">
<StackPanel.DataContext>
<local:CustomerViewModel />
</StackPanel.DataContext>
<TextBlock Text="{Binding Path=FirstName}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding Path=LastName}" />
</StackPanel>
<StackPanel
HorizontalAlignment="Left"
VerticalAlignment="top"
DockPanel.Dock="Top"
Orientation="Horizontal">
<ListBox ItemsSource="{Binding Source={StaticResource FileNames}}" />
</StackPanel>
<StackPanel
HorizontalAlignment="Left"
VerticalAlignment="top"
DockPanel.Dock="Top"
Orientation="Horizontal">
<ComboBox
ItemsSource="{Binding Source={StaticResource Directories}}"
SelectedIndex="0" />
</StackPanel>
<StackPanel
HorizontalAlignment="Left"
VerticalAlignment="top"
DockPanel.Dock="Top"
Orientation="Horizontal">
<StackPanel.DataContext>
<local:SystemInformationViewModel />
</StackPanel.DataContext>
<TextBlock Text="{Binding Path=CurrentTime}" />
</StackPanel>
</DockPanel>
在XAML中定义DataContext的一个优点是您的数据在Expression Blend设计模式中显示,而Expression Blend允许您在GUI中做很多事情,例如从您的数据源等中选择字段as shown here。
我已经读过绑定 ADO.NET对象不能绑定在XAML中(虽然我不明白为什么你可以为它们编写一个可以从XAML绑定的最小包装器。)< / p>
奇怪的是 WPF团队在制作WPF MVVM模板时用代码定义了DataContext,这很快就使得在Expression Blend中编辑你的视图变得不切实际,因为你的数据没有出现在设计中模式通常是布局的重要部分。
所以我认为必须有一些优势在代码中设置DataContext而不是XAML,任何人都知道它是什么?
答案 0 :(得分:15)
你可以(可能在2009年你不能)通过使用d:DataContext
属性来获得两全其美。如果你尚未做好准备,你不需要任何ViewModelLocator
craziness: - )
首先确保在根元素中定义了以下XML命名空间:
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
然后,您可以将以下属性添加到xaml中的元素:
d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True, Type=vm:CustomerInsightViewModel}"
在你的xaml代码隐藏中:
public CustomerInsightUserControl()
{
InitializeComponent();
if (!DesignerProperties.IsInDesignTool)
{
DataContext = new CustomerInsightViewModel();
}
}
然后在你的ViewModel中:
public CustomerInsightViewModel()
{
if (IsInDesignMode)
{
// Create design time data
Customer = new Customer() {
FirstName=...
}
}
else {
// Create datacontext and load customers
}
}
不要错过IsDesignTimeCreatable=True
,否则Blend将无法实例化您的课程
答案 1 :(得分:5)
我不喜欢让Expression Blend尝试实例化我的数据对象。
我通过代码设置DataContext,我可以使用依赖注入来注入适当的对象,服务,提供程序或我用来查找代码的其他内容。
答案 2 :(得分:1)
在代码隐藏中使用它可以很容易地使用unity注入datacontext。
答案 3 :(得分:1)
可能有一种解决方案,使用DataObjectProvider来掩盖数据在XAML之外实例化的事实。
它将说明DataContext的类型,这对于Blend来说应该足以获取属性。
我还没有尝试过这个,所以请耐心等待,但这当然值得研究。
答案 4 :(得分:1)
请参阅Rob关于Blend中设计时数据的文章:http://www.robfe.com/2009/08/design-time-data-in-expression-blend-3/
答案 5 :(得分:1)
也应该可以使用ObjectDataProvider来建立一个使用Unity或其他IOC的对象工厂,如此暗示......
http://social.msdn.microsoft.com/Forums/en/wpf/thread/1ff9e90e-302e-436e-bab3-ca4bad2b85af
特别是......
http://www.codeproject.com/Articles/43806/WPF-Ninject-Dojo-The-Data-Provider.aspx
答案 6 :(得分:0)
根据我的经验,最好至少针对它将呈现的数据样本设计界面布局。否则就是对廉价的见解和昂贵的疏忽视而不见。