当组合值设置为值- MVVM时,禁用WPF数据网格中的单元格

本文关键字:数据网 数据 网格 WPF 单元格 禁用 设置 组合 MVVM | 更新日期: 2023-09-27 18:06:13

我有一个具有DataGridComboBoxColumn列的DataGrid,我需要启用或禁用另一列中的复选框单元格,但我的代码似乎不起作用。

我有以下代码定义我的组合列:

<DataGridComboBoxColumn Header="Location"
 SelectedValueBinding="{Binding LocationId, Mode=TwoWay}"
 SelectedValuePath="LocationId"
 DisplayMemberPath="LocationText"
 TextBinding="{Binding Location, Mode=TwoWay}">

这是我的复选框列的代码:

<DataGridCheckBoxColumn Header="Active" 
 Binding="{Binding IsActive}">
   <DataGridCheckBoxColumn.CellStyle>
     <Style TargetType="DataGridCell">
       <Style.Triggers>
         <DataTrigger Binding="{Binding SelectedLineItem.Location}" 
          Value="01">
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>                                        
       </Style.Triggers>
     </Style>
  </DataGridCheckBoxColumn.CellStyle>
</DataGridCheckBoxColumn>

我已经添加了一个DataTrigger来尝试检测何时Location字段更改为01,并且基于此,我试图禁用选中行的复选框单元格,但它不起作用。

我还需要根据其他值选中/取消选中组合。

你知道我该怎么做吗?

更新1:

好吧,我已经取得了一些进展(侥幸!),现在我的触发器正在踢,但由于某种原因,每当我改变我的下拉位置为选定单元格,它改变了所有行的值相同的值。

下面是我的下拉栏的完整代码:

<DataGridComboBoxColumn Header="Location"
    SelectedItemBinding="{Binding DataContext.SelectedLineItem.SelectedLocation, 
     RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, 
    Mode=TwoWay}"
    SelectedValuePath="LocationId"
                        DisplayMemberPath="LocationText"
                        TextBinding="{Binding Location, Mode=TwoWay}">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="ItemsSource" Value="{Binding DataContext.Locations, 
          RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
            <Setter Property="IsReadOnly" Value="True"/>
            <Setter Property="FontSize" Value="14"/>
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="ItemsSource" Value="{Binding DataContext.Locations, 
             RelativeSource={RelativeSource FindAncestor, 
             AncestorType={x:Type Window}}}"/>
            <Setter Property="SelectedItem" Value="{Binding DataContext.SelectedLocation, 
             RelativeSource={RelativeSource FindAncestor, 
             AncestorType={x:Type Window}}}"/>
            <Setter Property="IsReadOnly" Value="False"/>
            <Setter Property="IsEditable" Value="True"/>
            <Setter Property="FontSize" Value="14"/>
            <EventSetter Event="KeyUp" Handler="LocationColumn_KeyUp"></EventSetter>
            <Style.Triggers>
                <Trigger Property="IsKeyboardFocusWithin" Value="True">
                    <Setter Property="IsDropDownOpen" Value="true" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>

这里是我的复选框列的完整代码(不要担心触发器做什么-它们是测试触发器):

<DataGridCheckBoxColumn Header="Active" Binding="{Binding IsActive}">
    <DataGridCheckBoxColumn.CellStyle>
        <Style TargetType="DataGridCell">
            <Style.Triggers>
                <DataTrigger Binding="{Binding SelectedLocation.LocationId}" Value="1">
                    <Setter Property="Background" Value="Green" />
                </DataTrigger>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="" >
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="01" >
                    <Setter Property="IsEnabled" Value="True" />
                </DataTrigger>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="02" >
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="03" >
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridCheckBoxColumn.CellStyle>
</DataGridCheckBoxColumn>

谁能弄清楚为什么我所有的行现在被设置,当我改变一个组合值?

谢谢。

当组合值设置为值- MVVM时,禁用WPF数据网格中的单元格

感谢@Freeman为我们指出了正确的方向。

我最终弄清楚了,我设法完全让它工作的唯一方法是在XAML中设置属性并在我的ViewModel中应用一些基本逻辑的组合。

完整的解释如下:

我有一个DataGridComboBoxColumn绑定到我的SelectionLocation属性,属于我的行ViewModel

get { return this._selectedLocation; }
set { Set(() => SelectedLocation, ref this._selectedLocation, value); }
现在关于XAML中的绑定:
<DataGridComboBoxColumn Header="Location"
    SelectedItemBinding="{Binding SelectedLocation, Mode=TwoWay}"
    SelectedValuePath="LocationId"
    DisplayMemberPath="LocationText">

这是我的第一个问题,因为每当我从组合中选择一个项目时,它没有调用/触发我的SelectedLocation ViewModel的setter部分。通过添加UpdateSourceTrigger=PropertyChanged:

修复了这个问题。
<DataGridComboBoxColumn Header="Warehouse"
    SelectedItemBinding="{Binding SelectedLocation, Mode=TwoWay,
                          UpdateSourceTrigger=PropertyChanged}"
    SelectedValuePath="LocationId"
    DisplayMemberPath="LocationText">
关于复选框列,XAML定义为:
<DataGridCheckBoxColumn Header="Active" Binding="{Binding IsActive, Mode=TwoWay>
    <DataGridCheckBoxColumn.ElementStyle>
        <Style TargetType="CheckBox">
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Center" />
    </DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>

再次,当选中和取消选中我的复选框时,它没有触发我的IsActive属性的setter,它属于与'SelectedLocation'属性相同的ViewModel。

为了解决这个问题,我最终添加了UpdateSourceTrigger=PropertyChanged:
<DataGridCheckBoxColumn Header="Active" Binding="{Binding IsActive, Mode=TwoWay, 
     UpdateSourceTrigger=PropertyChanged}">
    <DataGridCheckBoxColumn.ElementStyle>
        <Style TargetType="CheckBox">
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Center" />
    </DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>

现在已经对Combo和复选框列的绑定问题进行了排序,还剩下一件事。有条件的选择。这是通过使用XAML中的DataTrigger和我的ViewModel中的代码的组合来排序的。

XAML负责启用/禁用复选框,就像从SelectedLocation:

中选择一样
<DataGridCheckBoxColumn Header="Active" Binding="{Binding IsActive, Mode=TwoWay, 
     UpdateSourceTrigger=PropertyChanged}">
    <DataGridCheckBoxColumn.ElementStyle>
        <Style TargetType="CheckBox">
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Center" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="01" >
                    <Setter Property="IsEnabled" Value="True" />
                </DataTrigger>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="02" >
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="03" >
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>

在我的ViewModel中,每当SelectedLocation setter被触发时,它现在应用相同的规则,即检查位置是否为01,02或03,它将设置我的IsActive属性,因此选择/取消选中复选框:

public LocationViewModel SelectedLocation
{
    get { return this._selectedLocation; }
    set
    {
        Set(() => SelectedLocation, ref this._selectedLocation, value);
        if (this._selectedLocation.LocationText == "01")
            this.IsActive = false;
        else if (this._selectedLocation.LocationText == "02")
            this.IsActive = true;
        else if (this._selectedLocation.LocationText == "03")
        {
            this.IsActive = false;
        }
    }
}

这显然不是理想的,但它的工作完全符合预期。理想的解决方案是根据XAML中的条件将IsChecked设置为true或false,如下所示:

<DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="02" >
<Setter Property="IsChecked" Value="True" />
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>

但无论出于何种原因,当我使用这个方法时,当我手动选中复选框时,它将触发IsActive setter,但它不会基于触发规则触发它,从而使这个属性无用,我不能拥有。

不管怎样,我想就这样了。

我不得不发布一个更新作为我的惊喜,而复选框被禁用使用

<DataGridCheckBoxColumn Header="Active" Binding="{Binding IsActive, Mode=TwoWay, 
     UpdateSourceTrigger=PropertyChanged}">
    <DataGridCheckBoxColumn.ElementStyle>
        <Style TargetType="CheckBox">
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Center" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="01" >
                    <Setter Property="IsEnabled" Value="True" />
                </DataTrigger>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="02" >
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
                <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="03" >
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>

只是暂时禁用。双击单元格实际上启用了单元格,然后重新启用了复选框!完全没有意义,让你禁用一个复选框,然后在单元格进入编辑模式时重新启用它!!

无论如何,幸运的是,有一个工作是禁用单元格而不是复选框。这可以通过使用CellStyle而不是ElementStyle:

来实现。
<DataGridCheckBoxColumn.CellStyle>
    <Style TargetType="DataGridCell">
        <Style.Triggers>
            <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="01" >
                <Setter Property="IsEnabled" Value="True" />
            </DataTrigger>
            <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="02" >
                <Setter Property="IsEnabled" Value="False" />
            </DataTrigger>
            <DataTrigger Binding="{Binding SelectedLocation.LocationText}" Value="03" >
                <Setter Property="IsEnabled" Value="False" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</DataGridCheckBoxColumn.CellStyle>

您正在将复选框绑定到SelectedLineItem.Location。但是我可以看到这个属性没有绑定到组合框的任何地方。你已经将组合框的TextBinding绑定到Location。尝试将其更改为SelectedILineItem。还有位置。然后复选框将被绑定到组合框中的键入值。

如果你想根据组合框的选择值启用/禁用复选框,要么你应该将组合框的SelectedValuePath绑定到这个属性,要么将你的复选框绑定到SelectedItem。和触发条件,以匹配组合框的绑定。

如果我正确理解了你的问题,我认为你可以尝试这种方式。我在一个组合框中绑定了一个国家列表,并根据选择的某个值禁用了另一列。

Xaml代码看起来像

<Window.Resources>
        <staticData:CountryList x:Key="CountryList"/>
    </Window.Resources>
    <Grid>
        <DataGrid ItemsSource="{Binding SampleList}"  AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Countries" Width="100">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding SelectedCountry}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <ComboBox Height="22" Grid.Row="0"
                                        ItemsSource="{StaticResource CountryList}"
                                        SelectedItem="{Binding SelectedCountry}">
                            </ComboBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
                <!-- Inputs -->
                <DataGridTextColumn Width="SizeToCells" Header="Inputs" MinWidth="100" Binding="{Binding Input}" >
                    <DataGridTextColumn.CellStyle>
                        <Style TargetType="DataGridCell">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding SelectedCountry}" Value="UK">
                                    <Setter Property="IsEnabled" Value="false"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </DataGridTextColumn.CellStyle>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

Viewmodel有

public class MainViewModel : ObservableObject
    {
        private List<SampleData> sampleList;
        public List<SampleData> SampleList
        {
            get { return sampleList; }
            set { Set(ref sampleList, value); }
        }
        private Country selectedItem;
        public Country SelectedItem
        {
            get { return selectedItem; }
            set { selectedItem = value; }
        }
        private ObservableCollection<Country> countries;
        public ObservableCollection<Country> CountriesList
        {
            get { return countries; }
            set { this.Set(ref countries, value); }
        }
        public MainViewModel()
        {
            CountriesList = new ObservableCollection<Country> { new Country { Id = 1, Name = "India" }, new Country { Id = 1, Name = "Australia" } };
            SampleList = new List<SampleData>
            {
                new SampleData
                {
                    Input = "shan", RowNum = 3, SelectedCountry = "India"
                },
                new SampleData
                {
                    Input = "raj", RowNum = 1, SelectedCountry =  "India"
                },
                new SampleData
                {
                    Input = "sfk", RowNum = 9,  SelectedCountry =  "India"
                },
                new SampleData
                {
                    Input = "ShanSfk", RowNum = 7,  SelectedCountry =  "India"
                }
            };
        }
    }

和列表

  public class CountryList : List<string>
    {
        public CountryList()
        {
            this.Add("India");
            this.Add("Australia");
            this.Add("UK");
        }
    }

根据组合框中国家的选择,单元格被启用或禁用。