I have a DataGrid and the columns and rows are added in the code behind.
MainWindow.xaml:
<DataGrid Name="dgResult" ItemsSource="{Binding}" AutoGenerateColumns="True" CanUserAddRows="False" ColumnWidth="*"/>
MainWindow.xaml.cs:
private void AddItemsToDataGrid()
{
List<Measurement> measurements = new List<Measurement>()
{
new Measurement(){ Address="1", Pressure="10", ErrorTemps=new List<ErrorTemp>()
{
new ErrorTemp(){Temp="10", Error="0.1", IsErrorOK =true}, new ErrorTemp() { Temp = "20", Error = "0.2", IsErrorOK =true }}
},
new Measurement(){ Address="1", Pressure="20", ErrorTemps=new List<ErrorTemp>()
{
new ErrorTemp(){Temp="10", Error="0.2", IsErrorOK =true}, new ErrorTemp() { Temp = "20", Error = "0.3", IsErrorOK =true }}
},
new Measurement(){ Address="1", Pressure="30", ErrorTemps=new List<ErrorTemp>()
{
new ErrorTemp(){Temp="10", Error="0.34", IsErrorOK =true}, new ErrorTemp() { Temp = "20", Error = "0.5", IsErrorOK =false }}
}
};
DataTable dataTable = new DataTable();
dataTable.Columns.Add(nameof(Measurement.Address));
dataTable.Columns.Add(nameof(Measurement.Pressure));
foreach(ErrorTemp error in measurements[0].ErrorTemps)
dataTable.Columns.Add(nameof(error.Error) "(" error.Temp ")");
List<string> row;
foreach (Measurement measurement in measurements)
{
row = new List<string>() { measurement.Address, measurement.Pressure };
foreach (ErrorTemp error in measurement.ErrorTemps)
row.Add(error.Error);
dataTable.Rows.Add(row.ToArray());
}
dgResult.ItemsSource = dataTable.DefaultView;//bez default view jest źle
}
Measurement.cs:
namespace DataGridCodeBehind
{
public class Measurement
{
public string Address { get; set; }
public string Pressure { get; set; }
public List<ErrorTemp> ErrorTemps { get; set; }
}
public class ErrorTemp
{
public string Temp { get; set; }
public string Error { get; set; }
public bool IsErrorOK { get; set; }
}
}
I want to change the cell background color depending on IsErrorOK
value. How can I do it in the code behind?
CodePudding user response:
if the maximum amount of ErrorTemps is known beforehand then skip the datatable and use the measurements directly
<DataGrid ItemsSource="{Binding Measurements}" AutoGenerateColumns="False" CanUserAddRows="False" ColumnWidth="*">
<DataGrid.Resources>
<DataTemplate x:Key="ErrorTempTemplate" DataType="{x:Type local:ErrorTemp}">
<TextBlock x:Name="txtError" Text="{Binding Error}" ToolTip="{Binding Temp}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsErrorOK}" Value="false">
<Setter TargetName="txtError" Property="Background" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Address" Binding="{Binding Address}"/>
<DataGridTextColumn Header="Pressure" Binding="{Binding Pressure}"/>
<DataGridTemplateColumn Header="Temp1">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl Content="{Binding ErrorTemps[0]}" ContentTemplate="{StaticResource ErrorTempTemplate}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Temp2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl Content="{Binding ErrorTemps[1]}" ContentTemplate="{StaticResource ErrorTempTemplate}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
if it has to be completely dynamic here a little messy solution
<DataGrid x:Name="blubb" ItemsSource="{Binding Measurements}" AutoGenerateColumns="True" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" AutoGeneratedColumns="DataGrid_AutoGeneratedColumns" CanUserAddRows="False" ColumnWidth="*">
<DataGrid.Resources>
<Style x:Key="ErrorTempstyle" TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding Tag.IsErrorOK, RelativeSource={RelativeSource Self}}" Value="false">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
</DataGrid>
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
e.Cancel = e.PropertyName == nameof(Measurement.ErrorTemps);
}
private void DataGrid_AutoGeneratedColumns(object sender, System.EventArgs e)
{
var datagrid = (DataGrid)sender;
var firstItem = (Measurement)datagrid.Items[0];
for (int i = 0; i < firstItem.ErrorTemps.Count; i )
{
var s = new Style { TargetType = typeof(DataGridCell), BasedOn = (Style)datagrid.Resources["ErrorTempstyle"], Setters = { new Setter(TagProperty, new Binding($"ErrorTemps[{i}]")) } };
datagrid.Columns.Add(new DataGridTextColumn { Header = firstItem.ErrorTemps[i].Temp, CellStyle = s, Binding = new Binding($"ErrorTemps[{i}].Error") });
}
}
CodePudding user response:
Second solution works fine if I generate Measurments in MainViewModel constructor:
public MainViewModel()
{
OpenCommand = new DelegateCommand(OpenHandler);
GenerateList();
}
But if I will insert button, after pressing it I select text files and generate Measurements. I use button Command to do it.:
MainViewModel.cs:
public class MainViewModel : BindableBase
{
public ObservableCollection<Measurement> Measurements { get; set; } //= new ObservableCollection<Measurement>();
public DelegateCommand OpenCommand { get; set; }
public MainViewModel()
{
OpenCommand = new DelegateCommand(OpenHandler);
}
private void OpenHandler()
{
GenerateList();
}
private void GenerateList()
{
Measurements = new ObservableCollection<Measurement>()
{
new Measurement(){ Address="1", Pressure="10", ErrorTemps=new List<ErrorTemp>()
{
new ErrorTemp(){Temp="10", Error="0.1", IsErrorOK =true}, new ErrorTemp() { Temp = "20", Error = "0.2", IsErrorOK =true }, new ErrorTemp() { Temp = "30", Error = "0.41", IsErrorOK =true }}
},
new Measurement(){ Address="1", Pressure="20", ErrorTemps=new List<ErrorTemp>()
{
new ErrorTemp(){Temp="10", Error="0.2", IsErrorOK =true}, new ErrorTemp() { Temp = "20", Error = "0.3", IsErrorOK =true }, new ErrorTemp() { Temp = "30", Error = "0.42", IsErrorOK =true }}
},
new Measurement(){ Address="1", Pressure="30", ErrorTemps=new List<ErrorTemp>()
{
new ErrorTemp(){Temp="10", Error="0.34", IsErrorOK =true}, new ErrorTemp() { Temp = "20", Error = "0.5", IsErrorOK =false }, new ErrorTemp() { Temp = "30", Error = "0.43", IsErrorOK =false }}
}
};
}
In the above example, I simplified code and generate Measurmenst list without selecting files. Now I have empty DataGrid. How to solve that?