这是我第一次发布问题。 我尽可能地简化了我的代码,以说明我正在寻找的内容。
我有一个视图模型(外部),其中包含另一个视图模型(内部)的可观察集合。 内部视图模型用于用户控件。 外部视图模型用于 MainWindow。 我只想为可观察集合中的每个项目显示一个用户控件。 但是,我在将UserControl的DataContext设置为ObservableCollection中的项目时遇到了问题。
内部视图模型(用于用户控件):
public class InnerViewModel : ViewModelBase
{
string _text;
public string Text
{
get { return _text; }
set { SetProperty<string>(ref _text, value); }
}
public InnerViewModel() { }
}
内部视图模型(用于用户控件):
public class OuterViewModel : ViewModelBase
{
ObservableCollection<InnerViewModel> _innerViewModels;
public ObservableCollection<InnerViewModel> InnerViewModels
{
get { return _innerViewModels; }
set { SetProperty<ObservableCollection<InnerViewModel>>(ref _innerViewModels, value); }
}
public OuterViewModel()
{
_innerViewModels = new ObservableCollection<InnerViewModel>();
}
public void Init()
{
InnerViewModels.Clear();
InnerViewModels.Add(new InnerViewModel { Text = "Item1" });
InnerViewModels.Add(new InnerViewModel { Text = "Item2" });
}
}
内部控制 XAML(为清洁而删除了最外层的标记)
<UserControl.DataContext>
<local:InnerViewModel />
</UserControl.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50px"></ColumnDefinition>
<ColumnDefinition ></ColumnDefinition>
<ColumnDefinition Width="50px"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Content="Header"></Label>
<Label Grid.Column="1" Content="{Binding Text}" ></Label>
<Label Grid.Column="2" Content="Footer"></Label>
</Grid>
主窗口 XAML
<Window.DataContext>
<local:OuterViewModel />
</Window.DataContext>
<Grid>
<ItemsControl ItemsSource="{Binding InnerViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:InnerControl></local:InnerControl> <!-- HOW DO I SET THE DATACONTEXT ON THIS??? -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
内部控制.cs代码:
public partial class InnerControl : UserControl
{
public InnerControl()
{
InitializeComponent();
}
}
主窗口.cs代码:
public partial class MainWindow : Window
{
OuterViewModel _vm;
public MainWindow()
{
InitializeComponent();
_vm = (OuterViewModel)DataContext;
_vm.Init();
}
}
视图模型库:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
结果:我运行时得到的屏幕截图
我按如下方式解决了这个问题:
更改了主窗口.cs以创建外部视图模型:
public partial class MainWindow : Window
{
OuterViewModel _vm;
public MainWindow()
{
InitializeComponent();
_vm = new OuterViewModel();
_vm.Init();
DataContext = _vm;
}
}
将主窗口更改为未设置数据上下文
<!-- Don't set DataContext here -->
<Grid>
<ItemsControl ItemsSource="{Binding InnerViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:InnerViewModel}">
<local:InnerControl DataContext="{Binding}"></local:InnerControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
将 InnerControl XAML 更改为未设置数据上下文:
<!-- Don't set DataContext here -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50px"></ColumnDefinition>
<ColumnDefinition ></ColumnDefinition>
<ColumnDefinition Width="50px"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Content="Header"></Label>
<Label Grid.Column="1" Content="{Binding Text}" ></Label>
<Label Grid.Column="2" Content="Footer"></Label>
</Grid>
在内部 VM 的视图中,您在视图中创建视图模型(视图优先),这意味着您在DataTemplate
中创建的视图具有与ItemsControl
提供的视图模型不同的视图模型。
您可以像这样再次覆盖它(不确定属性分配顺序):
<DataTemplate>
<local:InnerControl DataContext="{Binding}"/>
</DataTemplate>
如注释中所述,我不会在视图中创建 VM,而是使用类型化DataTemplates
隐式创建视图。