【发布时间】:2018-04-21 12:45:06
【问题描述】:
我对 WPF 中的 MVVM 比较陌生,并且几天来一直在尝试解决一个问题。我正在使用 dragablz 选项卡控件并绑定 ItemsSource,它是对象的 ObservableList。但是,Tab Item 的内容是一个 UserControl;它的数据上下文是null。我创建了一个简单的设置来演示我遇到的问题:
模型/视图模型类:
public class Item
{
public string Header { get; set; }
public ItemContent Body { get; set; }
}
public class ItemContent
{
public string Name { get; set; }
public string Description { get; set; }
}
class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ObservableCollection<Item> Items { get; set; }
}
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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfTestApplication"
xmlns:views="clr-namespace:WpfTestApplication.ViewModels"
xmlns:dragablz="clr-namespace:Dragablz;assembly=Dragablz"
xmlns:dockablz="clr-namespace:Dragablz.Dockablz;assembly=Dragablz"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<views:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Button Name="btnAdd" Content="Add" Click="btnAdd_Click" />
<dockablz:Layout Grid.Row="1">
<dragablz:TabablzControl HeaderMemberPath="Header" ItemsSource="{Binding Items}" SelectedIndex="1">
<dragablz:TabablzControl.ContentTemplate>
<DataTemplate DataType="{x:Type views:Item}">
<local:TabItemControl />
</DataTemplate>
</dragablz:TabablzControl.ContentTemplate>
</dragablz:TabablzControl>
</dockablz:Layout>
</Grid>
</Window>
选项卡项 XAML
<UserControl x:Class="WpfTestApplication.TabItemControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfTestApplication"
xmlns:views="clr-namespace:WpfTestApplication.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<views:ItemContent />
</UserControl.DataContext>
<Grid>
<TextBox Text="{Binding Body}" />
</Grid>
</UserControl>
还有 btnAdd_Click 事件
请注意,我并没有在我的实际代码中使用它,但这是一种无需添加命令即可动态添加选项卡项的快速而肮脏的方式。
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
((ViewModels.MainWindowViewModel)DataContext).Items.Add(new ViewModels.Item() { Header = "New One", Body = new ViewModels.ItemContent() { Name = "This One" } });
}
【问题讨论】:
-
<UserControl.DataContext> <views:Item /> </UserControl.DataContext>是吗? -
为 UserControl 定义 DataContext。我现在实际上已将其设置为
<view:ItemContent />。 -
数据上下文应该来自父级。在用户控件内设置 DC 是主要的代码异味。不要这样做。你不应该这样做。
-
您可能想阅读this answer,详细介绍 UC 设计的这个常见缺陷。
-
UserControl 的 DataContext 将是主窗口视图模型的 Items 集合中的任何内容。这就是你想要的吗?