【问题标题】:How to disable a specific DataGid Cell of a new row如何禁用新行的特定 DataGrid 单元格
【发布时间】:2017-07-25 10:22:16
【问题描述】:

我有一个简单的DataGrid,有两列

<DataGrid ItemsSource="{Binding Commands}" CanUserAddRows="True" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Value" Binding="{Binding Value}"/>
        <DataGridTemplateColumn Header="Command">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox ItemsSource="{Binding ComboItems}" SelectedValue="{Binding SelectedItem}">
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Converter={StaticResource ItemConverter}}"/>
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

我的目标是禁用带有新行ComboBox 的单元格。下图显示了我的DataGrid(绑定到两个项目的ObservableCollection)并标记了要禁用的列。

我已经尝试使用转换器禁用ComboBox

IsEnabled="{Binding Value, Converter={StaticResource DisableConverter}}"

但在我在第一列中输入值之前,转换器不会被调用。

希望有人可以帮助我!

【问题讨论】:

  • 是的,我正在使用 MVVM,ItemConverter 只是用于检查何时调用转换器的测试,应在显示第 1 列的值时启用 ComboBox。
  • 因为项目(ViewModel)尚未创建 - “新行”显示如果我向第一列添加值将创建的项目(所以我无法绑定到任何属性,因为后面没有对象)。这是默认的 DataGrid 行为,这基本上是我的问题。
  • 否,因为“新行”是对象的默认行。该对象是在我在 DataGrid 中设置值时创建的。但我想禁用组合框,直到创建项目。 (图为两个item的一个ObservableCollection)

标签: c# wpf xaml datagrid converter


【解决方案1】:

您可以将以下Style 应用于ComboBox

<ComboBox ItemsSource="{Binding ComboItems}" SelectedValue="{Binding SelectedItem}">
    <ComboBox.Style>
        <Style TargetType="ComboBox">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=DataContext,RelativeSource={RelativeSource AncestorType=DataGridRow}}" 
                                                         Value="{x:Static CollectionView.NewItemPlaceholder}">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ComboBox.Style>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource ItemConverter}}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

【讨论】:

  • 像魅力一样工作!谢谢!
【解决方案2】:

基于这个previous answer,你可以在Loaded事件处理函数中实现这个

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        var dataGridRow = FindChild(dataGrid, x =>
        {
            var element = x as DataGridRow;
            if (element != null && element.Item == System.Windows.Data.CollectionView.NewItemPlaceholder)
                return true;
            else
                return false;
        }) as DataGridRow;
        var combo = FindChild(dataGridRow, x =>
        {
            return x is ComboBox;
        }) as ComboBox;
        combo.IsEnabled = false;
    }

有了这个助手

    public static DependencyObject FindChild(DependencyObject parent, Func<DependencyObject, bool> predicate)
    {
        if (parent == null) return null;

        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);

            if (predicate(child))
            {
                return child;
            }
            else
            {
                var foundChild = FindChild(child, predicate);
                if (foundChild != null)
                    return foundChild;
            }
        }

        return null;
    }

【讨论】:

  • 感谢您的解决方案。它按预期工作。但是这个解决方案有效——我更喜欢@mm8 的解决方案,因为我不需要任何代码隐藏。
猜你喜欢
  • 2013-04-10
  • 1970-01-01
  • 2017-11-29
  • 2023-03-22
  • 2011-12-11
  • 2012-04-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多