将 DataGridComboBoxCollumn 绑定到我的 ViewModel 中的 IObservableCollection

Binding a DataGridComboBoxCollumn to a IObservableCollection in my ViewModel

我现在正在进行一个学习项目,其中有两个模型。用户和角色。用户具有对一个角色对象的引用。我将两者的集合作为 IObservableCollection(用户和角色)存储在我的 ViewModel 中。 在我的视图中,我有一个 DataGrid,其中我使用 Caliburn.Micro 将 DataContext/ItemsSource 设置为我的 ViewModel 中的用户集合,在 DataGrid 中我有一个 DataGridComboBoxColumn,它应该显示角色的所有条目来自我的 ViewModel 的集合,但我无法访问它们。

我已经尝试了我在 Internet 上找到的所有内容。 RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}} 以及我发现的每个变体,使用 DataGridComboBoxColumn.ElementStyle / DataGridComboBoxColumn.EditingElementStyle 方法,我通过它们设置 ItemsSource,DisplayMember 等。甚至远程都没有工作。

这是我目前的观点

<UserControl x:Class="UserModule.Views.User.ListUsersView"
             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:UserModule.Views.User"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <StackPanel>
        <DataGrid x:Name="Users" AutoGenerateColumns="False" CanUserAddRows="True">
            <DataGrid.Columns>
                <DataGridTextColumn x:Name="Username" Header="Username" Binding="{Binding Username}"/>
                <DataGridTextColumn x:Name="Role" Header="Role" Binding="{Binding Role.RoleName}"/> <!--This is the current Role the User has-->
                <DataGridComboBoxColumn Header="Group" 
                             ItemsSource="{Binding Path=DataContext.Roles, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" DisplayMemberPath="RoleName" />
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel>
</UserControl>

这是我当前 ViewModel 的(相关部分),我从中获取数据

namespace UserModule.ViewModels.User
{
    using Caliburn.Micro;

    public class ListUsersViewModel : Screen
    {
        private IObservableCollection<User> users;
        private User selectedUser;

        /// <summary>
        /// Constructor for ListUserViewModel
        /// </summary>
        public ListUsersViewModel()
        {
            this.LoadData(); //Loads data from database into Users and Roles
        }

        /// <summary>
        /// Loaded User model-objects from database
        /// </summary>
        public IObservableCollection<User> Users
        {
            get => this.users;
            set
            {
                this.users = value;
                this.NotifyOfPropertyChange();
            }
        }

        public IObservableCollection<Role> Roles { get; set; }

    }
}

两个集合都填充了数据。用户名和角色名显示正确,但我无法让 ComboBox 显示有关角色的任何信息,甚至 Caliburn.Micro 错误消息 "No View found for x" 也没有。另一方面,如果我在我的 DataGrid 之外使用 ComboBox,同时简单地绑定到角色,我当然会为角色中的每个角色收到此错误消息。

好的,我现在有点解决了这个问题...通过不使用 DataGridComboBoxColumn 而是通过 DataGridTemplateColumn 创建我自己的 ComboBoxColumn,它在 CellTemplate 中有一个 TextBlock,在 CellEditingTemplate 中有一个 ComboBox

<DataGrid.Columns>
     <DataGridTextColumn Binding="{Binding Username}"/>
     <DataGridTemplateColumn>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Role.RoleName}"/>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
        <DataGridTemplateColumn.CellEditingTemplate>
            <DataTemplate>
                    <ComboBox ItemsSource="{Binding Path=DataContext.Roles, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" DisplayMemberPath="RoleName"/>
            </DataTemplate>
        </DataGridTemplateColumn.CellEditingTemplate>
    </DataGridTemplateColumn>
</DataGrid.Columns>

您正在让 setter 侦听 UI 中的更改,但没有触发更新以更改值:

使 class 继承自 INotifyPropertyChanged 并使用类似的东西:

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string name)
{
      PropertyChangedEventHandler handler = PropertyChanged;

      if (handler != null)
      {
          handler(this, new PropertyChangedEventArgs(name));
      }
}

并在 setter 中触发 OnPropertyChanged()