每行具有相同动态内容的WPF DataGrid ComboBoxColumn

yc0p9oo0  于 2023-05-19  发布在  其他
关注(0)|答案(1)|浏览(169)

DataGrid中,我希望ComboBoxColumn的每行具有相同的内容。ComboBox的内容是动态的:如果您在ComboBox中为一行选择了一个值,则此选定值不能为其他行选择。我目前的问题是ComboBox的内容在前面的几行中没有更新。我举了一个简单的例子来解释:

XAML

<StackPanel>
    <DataGrid ItemsSource="{Binding Items}"
              SelectedItem="{Binding SelectedItem}"
              Height="auto"
              CanUserAddRows="False"
              AutoGenerateColumns="False"
              IsReadOnly="False">
        <DataGrid.Columns>
            <DataGridTemplateColumn Width="*" Header="Key" MinWidth="100">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox ItemsSource="{Binding DataContext.KeyList, RelativeSource={RelativeSource Findancestor, AncestorType={x:Type Window}}}"
                                  SelectedItem="{Binding SelectedKey, UpdateSourceTrigger=PropertyChanged}"
                                  DisplayMemberPath="Name">
                            <ComboBox.ItemContainerStyle>
                                <Style TargetType="ComboBoxItem">
                                    <Setter Property="IsEnabled" Value="{Binding IsSelectable}"/>
                                </Style>
                            </ComboBox.ItemContainerStyle>
                        </ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn Header="Value" Binding="{Binding Value, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
        </DataGrid.Columns>
    </DataGrid>
    <Button Margin="0,10,0,0" Width="80" Content="Add Row" Command="{Binding AddRowCommand}"/>
</StackPanel>

主虚拟机

public class MainVM
{
    private ObservableCollection<ItemsVM> myItems;

    private List<Key> myKeyList = new List<Key>()
    {
        new Key("Item 1", true),
        new Key("Item 2", true),
        new Key("Item 3", true)
        
    };

    public MainVM()
    {
        myItems = new ObservableCollection<ItemsVM>();

        AddRowCommandAction();
    }

    public ObservableCollection<ItemsVM> Items => myItems;
    public ItemsVM SelectedItem { get; set; }
    public List<Key> KeyList => myKeyList;

    private void SetKeySelectability()
    {
        foreach (Key item in myKeyList)
        {
            if (myItems.Any(x => x.SelectedKey == item))
                item.IsSelectable = false;
            else
                item.IsSelectable = true;
        }
    }

    private RelayCommand myAddRowCommand;
    public RelayCommand AddRowCommand
    {
        get
        {
            if (myAddRowCommand == null)
                myAddRowCommand = new RelayCommand(AddRowCommandAction);

            return myAddRowCommand;
        }
    }

    private void AddRowCommandAction()
    {
        myItems.Add(new ItemsVM
        { 
            Value = string.Format("Row {0}", myItems.Count + 1),
            SelectedKey = myKeyList.FirstOrDefault(x => x.IsSelectable == true)
        });

        SetKeySelectability();
    }
}

其他类别

public class ItemsVM
{ 
    public string Value { get; set; }
    public Key SelectedKey { get; set; }
}

public class Key : ObservableObject
{
    private bool _IsSelectable;

    public Key(string name, bool isselectable)
    { 
        Name = name;
        IsSelectable = isselectable;
    }

    public string Name { get; set; }
    public bool IsSelectable
    { 
        get { return _IsSelectable; } 
        set
        {
            if (_IsSelectable == value) return;
            
            _IsSelectable = value;
            OnPropertyChanged(nameof(IsSelectable));
        }
    }
}

在开始时,我们可以看到Item 1被选择为Row 1Item 1IsSelectable属性被更新并且不再可选:

在点击Button添加一行后,我得到了这个(这是正确的)。两个使用的值不可选,Row 1'sComboBox具有相同的值。

现在,我更改Row 1的值:我们可以看到,Item 1是不可选择的(但它应该是),Row 2'sComboBox也不是最新的(Item 3是可选择的,不应该和Item 1没有发布)

我如何才能做到这一点?

lp0sw83n

lp0sw83n1#

如果我理解正确的话,要做到这一点,需要在ComboBox的选中项发生变化时,更新Key示例的IsSelectable属性。
在您的情况下,每当SelectedKey更改时,您需要从ItemsVM类中引发PropertyChanged事件。需要通知MainVM更新Key示例的IsSelectable属性。
以下是你可以做的:
1.使ItemsVM类实现INotifyPropertyChanged:

public class ItemsVM : INotifyPropertyChanged
{ 
    public string Value { get; set; }

    private Key _selectedKey;
    public Key SelectedKey 
    { 
        get
        {
            return _selectedKey;
        }
        set
        {
            if (_selectedKey == value) return;
            _selectedKey = value;
            OnPropertyChanged(nameof(SelectedKey));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

1.在MainVM类中,订阅ItemsVM示例的PropertyChanged事件:

private void AddRowCommandAction()
{
    var newItem = new ItemsVM
    { 
        Value = string.Format("Row {0}", myItems.Count + 1),
        SelectedKey = myKeyList.FirstOrDefault(x => x.IsSelectable == true)
    };

    newItem.PropertyChanged += ItemPropertyChanged;
    myItems.Add(newItem);

    SetKeySelectability();
}

1.将ItemPropertyChanged方法添加到MainVM以处理事件:

private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(ItemsVM.SelectedKey))
    {
        SetKeySelectability();
    }
}

1.最后,在适当的时候取消订阅PropertyChanged事件,以避免内存泄漏。例如,您可能会在某个时候从myItems中删除ItemsVM示例,并且您需要在执行此操作之前取消订阅:

private void RemoveItem(ItemsVM item)
{
    item.PropertyChanged -= ItemPropertyChanged;
    myItems.Remove(item);
}

相关问题