Reputation: 3
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.
Upvotes: 0
Views: 209
Reputation: 1312
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 Label
s.
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:
[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
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; }
}
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;
}
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>
<Window.Resources>
<local:IntEqualsToVisibilityConverter x:Key="ValueToVisibilityConverter" />
</Window.Resources>
It works for me.
What we learned here is:
DataGrid
rowIMultiValueConverter
Upvotes: 0
Reputation: 12276
When they were designing WPF they took some fundamental design choices.
One design choice was to favour binding over the VB6 pattern devs used of building controls and adding them into comboboxes or gridviews.
It is not particularly obvious how you get at a row out a datagrid in code. The designers did not envision that to be the way devs would work with rows.
You could do this in code:
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;
Here my datagrid is called dg ( obviously ).
This approach relies on the selected index of the combobox being the same as the index of the row in the datagrid you want to gray. I am just using IsEnabled here but you could do other things with that row once you have a reference if you prefer.
You could use a binding and converter usually to set a value on some property. You need both the index of the row considered and the value of whatever is set in the combobox. You'd need a multibinding and multiconverter.
It would also be good if this multiconverter was at least somewhat re-usable.
We also need some way to get at that row, which would be to use rowstyle.
Bringing all that together my xaml would look like:
<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 is being used here to give the row index.
The multiconverter looks like:
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();
}
Which can be used without declaring it as a resource because it's a markupextension as well as a converter.
That multi binding and converter could instead be used in a datatrigger to apply a style to your particular row.
This isn't super complicated but it's also not super simple and you can perhaps see why it's more usual to work with bound collections of viewmodels which can have logic encapsulated in code within them and bind properties directly to them.
Upvotes: 1