Search code examples
c#wpfdatagrid

How do I get a certain row within a wpf datagrid, which is formed by DataGridTextColumns?


I got a datagrid of 3 rows.
The datagrid is generated by a class(datagrid.class) which writes three columns a time.
This process performs 3 times so that'a 9-cell datagrid.
Please noted that it's formed by columns.
And I have a combobox of 3 comboboxItems.
The combobox_SelectionChanged method is wanted to be set like this:

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;
}

And my datagrid:

<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>

Datagrid.cs :

namespace myq

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

Whole 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;
    }
} 

}

My Question is : How do i write sentense 1? I searched for quite some time didn't find a solution.

I googled this, many of the answers are about selected datagrid rows.

I don't need to select any of the row.The interact within comboboxItem selection and one row of the datagrid is set.

Also I tried sth like:

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

and the return is:

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

Thanks for taking concerns to here. Any hint will be appreacited.


Solution

  • My Question is : How do i write sentense 1?

    You don't. What I've learned about WPF is to stay away from writing code in favour of using bindings and other mechanisms that WPF provides.

    To solve your problem you can basically do, what I've described in another thread here: How to use a xaml control to show/hide other controls?

    In your case you can perhaps modify the ValueConverter to return Visibility instead of bool. Make sure you name your ComboBox and then, when generating your DataGrid rows, you add binding to each row's Visibility property in a similar way that I've described for the IsEnabled of the Labels.

    EDIT: I've done some search and prototyping and this is what I've found. Basically, what I've written earlier is not that straightforward when coming to DataGrid. But, I've developed a solution for you still hugely based on my initial concept. With the code you've provided I'd do the following:

    • first implement a multivalue converter wee need to compare two values where both are kind of dynamic:
    [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();
        }
    }
    
    • then you need to alter your datagrid class (by the way, try not to "reuse" the typenames, give a meaningful name to the class) so it holds the combobox reference, row id and creates the binding:
    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; }
    }
    
    • then you slightly alter your MainWindow constructor, to you provide the DataContext and give the id to each row that corresponds to the combobox selected index:
    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;
    }
    
    • and finally, in your DataGrid, you define RowStyle as following (you bind the row's Visibility property to Combobox1's SelectedItem and row's RowId with multivalue converter):
    <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>
    
    • don't forget to add window's resource with the miltivalue converter:
    <Window.Resources>
        <local:IntEqualsToVisibilityConverter x:Key="ValueToVisibilityConverter" />
    </Window.Resources>
    

    It works for me.

    What we learned here is:

    • how to use bindings
    • how to set the properties on DataGrid row
    • how to implement and use IMultiValueConverter