【问题标题】:How do I get a certain row within a wpf datagrid, which is formed by DataGridTextColumns?如何在由 DataGridTextColumns 形成的 wpf 数据网格中获取特定行?
【发布时间】:2023-02-08 15:53:19
【问题描述】:

我有一个 3 行的数据网格。
数据网格由一次写入三列的类(datagrid.class)生成。
此过程执行 3 次,这样就形成了一个 9 单元数据网格。
请注意,它是由列组成的。
我有一个包含 3 个组合框项的组合框。
combobox_SelectionChanged 方法需要这样设置:

private void Combobox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ComboOpticalInput.SelectedIndex == 2)
// Show 3 all rows,1st row gets grayish      
sentense 1;
    else if (ComboOpticalInput.SelectedIndex == 1)
    // Show 3 all row, 2nd row gets grayish 
    sentense 2;
       else
       // Show 3 all row, 3rd row  gets grayish 
       sentense 3;
}

我的数据网格:

<DataGrid Grid.Row="1" Grid.RowSpan="3" Grid.Column="0" Grid.ColumnSpan="3" Name="DataGrid1" RowHeaderWidth="0" AutoGenerateColumns="False" >
        <DataGrid.Columns>
            <DataGridTextColumn Header="option" Width="5*" IsReadOnly="True" x:Name="DGOP1" Binding="{Binding option}" />
            <DataGridTextColumn Header="Value1" Width="3*" x:Name="DGOP2" Binding="{Binding PValue}" />
            <DataGridTextColumn Header="Value2" Width="2*" x:Name="DGOP3" Binding="{Binding QValue}">
                
            </DataGridTextColumn>
        </DataGrid.Columns>
</DataGrid>

数据网格.cs:

namespace myq

{public class datagrid
  {
    public string option { get; set; }
    public double PValue { get; set; }
    public string QValue { get; set; }
  }
}

整个 XAML:

<Window x:Class="myq.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:myq"
    mc:Ignorable="d"
    Title="MainWindow" Height="550" Width="600">
  <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*"></RowDefinition>
        <RowDefinition Height="2*"></RowDefinition>
        <RowDefinition Height="2*"></RowDefinition>
        <RowDefinition Height="2*"></RowDefinition>
        <RowDefinition Height="2*"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <StackPanel Margin="10" Grid.Row="0" Grid.Column="2">
        <ComboBox Name="Combobox1" SelectedIndex="-1" SelectionChanged="Combobox1_SelectionChanged">
            <ComboBoxItem>Item #1</ComboBoxItem>
            <ComboBoxItem>Item #2</ComboBoxItem>
            <ComboBoxItem>Item #3</ComboBoxItem>
        </ComboBox>
    </StackPanel>
    <DataGrid Grid.Row="1" Grid.RowSpan="3" Grid.Column="0" Grid.ColumnSpan="3" Name="DataGrid1" RowHeaderWidth="0" AutoGenerateColumns="False" >
        <DataGrid.Columns>
            <DataGridTextColumn Header="option" Width="5*" IsReadOnly="True" x:Name="DGOP1" Binding="{Binding option}" />
            <DataGridTextColumn Header="Value1" Width="3*" x:Name="DGOP2" Binding="{Binding PValue}" />
            <DataGridTextColumn Header="Value2" Width="2*" x:Name="DGOP3" Binding="{Binding QValue}">                    
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
  </Grid>
</Window>

XAML.cs:

namespace myq
{

  public partial class MainWindow : Window
  {
  public ObservableCollection<datagrid> FirstProperties { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        FirstProperties = new()
        {
            new datagrid()
            {
                option = "Short",
                PValue = 550,
                QValue = "[nm]",
            },
            new datagrid()
            {
                option = "Long",
                PValue  = 3800,
                QValue = "[nm]",
            },
            new datagrid()
            {   option = "Medium",
                PValue  = 6,
                QValue = "[]"
            }
        };
        DataGrid1.ItemsSource = FirstProperties;
    }

    private void Combobox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        Window win1 = new Window();
        if (Combobox1.SelectedIndex == 2)
            win1.Show();

        else if (Combobox1.SelectedIndex == 1)
            win1.Close();
        else;
    }
} 

}

我的问题是:我如何写句子 1? 我搜索了很长时间没有找到解决方案。

我用谷歌搜索了这个,很多答案都是关于选定的数据网格行的。

我不需要选择任何行。comboboxItem 选择中的交互和数据网格的一行已设置。

我也尝试过类似的东西:

DataGrid1.row[1].Foreground = new SolidColorBrush(Colors.Grey);

回报是:

>"datagrid" does not contain a definition for "row"

感谢您关注这里。任何提示将不胜感激。

【问题讨论】:

  • 一方面,不太清楚你到底在问什么?我思考您在问“如何根据组合框中的选择使数据网格中的特定行显示不同?”其次,您需要正确格式化您的代码,因为这会使其很难阅读 - 要么将所有这些行缩进 4 个前导空格,要么使用反引号 - “`”。 (你似乎已经添加了一些文本作为代码块,但那不是代码所以不确定如何/为什么)
  • 是的,你没看错。我会编辑我的代码,谢谢
  • 抱歉第一次使用 stackoverflow,我已经编辑过了。有没有办法让我获得数据网格的第一/第二/第三行?如果是,是否有办法将整行(或其中的元素)变成灰色?谢谢。

标签: c# wpf datagrid


【解决方案1】:

在设计 WPF 时,他们采用了一些基本的设计选择。

一种设计选择是支持绑定开发人员用于构建控件并将它们添加到组合框或网格视图中的 VB6 模式。

如何在代码中连续获取数据网格并不是特别明显。设计者没有预料到开发人员会以这种方式处理行。

您可以在代码中执行此操作:

    private void ComboInput_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (lastRowIndex > -1)
        {
            var lastrow = (DataGridRow)dg.ItemContainerGenerator.ContainerFromIndex(lastRowIndex);
            lastrow.IsEnabled = true;
        }

        var row = (DataGridRow)dg.ItemContainerGenerator.ContainerFromIndex(ComboInput.SelectedIndex);
        row.IsEnabled = false;
        lastRowIndex = ComboInput.SelectedIndex;
    }
    int lastRowIndex = -1;

这里我的数据网格被称为 dg(显然)。

此方法依赖于组合框的选定索引与要变灰的数据网格中的行的索引相同。我只是在此处使用 IsEnabled,但如果您愿意,可以在获得参考后对该行执行其他操作。

您通常可以使用绑定和转换器来设置某些属性的值。您需要考虑的行的索引和组合框中设置的任何值。你需要一个多绑定和多转换器。

如果这个多转换器至少在某种程度上是可重复使用的,那也很好。

我们还需要一些方法来获取该行,这将是使用 rowstyle。

将所有这些放在一起我的 xaml 看起来像:

    <DataGrid Name="dg" AutoGenerateColumns="False"
              AlternationCount="10000">
        <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
                <Setter Property="IsEnabled">
                    <Setter.Value>
                        <MultiBinding Converter="{local:IsMultiNotEqualConverter}">
                            <Binding Path="AlternationIndex" RelativeSource="{RelativeSource Self}"/>
                            <Binding Path="SelectedIndex" ElementName="ComboInput"/>
                        </MultiBinding>
                    </Setter.Value>
                </Setter>
            </Style>
        </DataGrid.RowStyle>

此处使用 Alternationindex 来提供行索引。

多转换器看起来像:

public class IsMultiNotEqualConverter : MarkupExtension, IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !values[0].Equals(values[1]);
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return null;
    }
    private static IsMultiNotEqualConverter _converter = null;
    public override object ProvideValue(IServiceProvider serviceProvider) => _converter ??= new IsMultiNotEqualConverter();
}

无需将其声明为资源即可使用,因为它既是标记扩展又是转换器。

该多重绑定和转换器可以改为在数据触发器中使用,以将样式应用于您的特定行。

这不是超级复杂,但也不是超级简单,您或许可以理解为什么使用视图模型的绑定集合更常见,这些视图模型可以将逻辑封装在代码中并将属性直接绑定到它们。

【讨论】:

  • 我会投赞成票,但作为 stackoverflow 的新成员,我还没有获得许可。我会尝试你的方法,看看我能做什么。非常感谢。
  • @rookieqt 你可以为你的问题标记答案。我想您会在每个可能的答案旁边看到一个复选标记。如果有人解决了它,那么你检查一下。如果提出了多个答案并且您的问题得到了解决,您可以选择最能解决问题的答案。
  • 记下了,谢谢。那个多转换器现在对我来说有点难。我会看看我能完成什么。顺便说一句,现在所有代码都上传了。
  • 我喜欢 MarkupExtension 转换器实现。
【解决方案2】:

我的问题是:我如何写句子 1?

你不知道。我对 WPF 的了解是远离编写代码,转而使用绑定和 WPF 提供的其他机制。

要解决你的问题,你基本上可以做,我在另一个线程中描述的:How to use a xaml control to show/hide other controls?

在您的情况下,您也许可以修改 ValueConverter 以返回 Visibility 而不是 bool。 确保命名你的ComboBox,然后在生成你的DataGrid 行时,你将绑定添加到每一行的Visibility 属性,方法与我为Label 的IsEnabled 描述的方式类似。

编辑:我做了一些搜索和原型设计,这就是我发现的。 基本上,当我来到DataGrid时,我之前写的并不是那么简单。但是,我已经在很大程度上基于我最初的概念为您开发了一个解决方案。 使用您提供的代码,我将执行以下操作:

  • 首先实现一个多值转换器,我们需要比较两个值,其中两个值都是动态的:
[ValueConversion(typeof(int[]), typeof(Visibility))]
public class IntEqualsToVisibilityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (targetType != typeof(Visibility) && targetType != typeof(Object))
            throw new InvalidOperationException($"The target must be a Visibility");
        return values.Length == 2 && (int)values[0] == (int)values[1] ? Visibility.Visible : Visibility.Collapsed;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
  • 然后您需要更改您的datagrid 类(顺便说一下,尽量不要“重复使用”类型名称,为该类提供一个有意义的名称)以便它保存组合框引用、行 ID 并创建绑定:
public class MyDatagridDataType
{
    public MyDatagridDataType(int rowId)
    {
        this.RowId = rowId;
    }

    public int RowId { get; private set; }

    public string? Option { get; set; }
    public double PValue { get; set; }
    public string? QValue { get; set; }
}
  • 然后你稍微改变你的 MainWindow 构造函数,你提供 DataContext 并为与组合框所选索引对应的每一行提供 id:
public MainWindow()
{
    InitializeComponent();
    this.DataContext = this;

    var firstProperties = new MyDatagridDataType[]
    {
        new MyDatagridDataType(0)
        {
            Option = "Short",
            PValue = 550,
            QValue = "[nm]",
        },
        new MyDatagridDataType(1)
        {
            Option = "Long",
            PValue = 3800,
            QValue = "[nm]",
        },
        new MyDatagridDataType(2)
        {
            Option = "Medium",
            PValue = 6,
            QValue = "[]"
        }
    };

    DataGrid1.ItemsSource = firstProperties;
}
  • 最后,在你的DataGrid中,你定义RowStyle如下(你将行的Visibility属性绑定到Combobox1的SelectedItem和行的RowId与多值转换器):
<DataGrid.RowStyle>
    <Style TargetType="{x:Type DataGridRow}">
        <Setter Property="Visibility">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource ValueToVisibilityConverter}">
                    <Binding ElementName="Combobox1" Path="SelectedIndex" />
                    <Binding Path="RowId" />
                </MultiBinding>
            </Setter.Value>
        </Setter> 
    </Style>
</DataGrid.RowStyle>
  • 不要忘记使用多值转换器添加窗口的资源:
<Window.Resources>
    <local:IntEqualsToVisibilityConverter x:Key="ValueToVisibilityConverter" />
</Window.Resources>

这个对我有用。

我们在这里学到的是:

  • 如何使用绑定
  • 如何设置DataGrid行的属性
  • 如何实现和使用IMultiValueConverter

【讨论】:

  • 获取部分解决方案,谢谢。但是我如何获得我的数据网格中某一行的描述(我在编辑中上传了它)? DataGrid1.row[1] 之类的东西不起作用。
  • 当您的类生成 DataGrid 时,您将绑定添加到代码隐藏中的行。尝试以这样的方式思考,不是您想要告诉您的行要做什么,而是相反 - 行本身绑定到其他一些元素。如果您有问题,是否可以分享您的网格生成代码的某些部分,以便我可以复制您的问题?
  • 我看到有人对我投了反对票。我想知道为什么。知道这样做的原因将有助于我改进未来的答案。
  • 我是 stakoverflow 的新成员,我没有投票权限,但我试过投票。再次感谢迈克。我将更新我的网格生成代码。
  • 谢谢@rookieqt,没问题。如果你不能让它工作,请告诉我,我会尝试为你准备一个示例代码。
猜你喜欢
  • 1970-01-01
  • 2019-12-11
  • 2014-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 2017-07-07
相关资源
最近更新 更多