将 ItemsControl 绑定到视图模型上的视图模型集合



这是我第一次发布问题。 我尽可能地简化了我的代码,以说明我正在寻找的内容。

我有一个视图模型(

外部),其中包含另一个视图模型(内部)的可观察集合。 内部视图模型用于用户控件。 外部视图模型用于 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隐式创建视图。

最新更新