Datagrid Column value bind? - c#

I need to accept only specific digits into a column in datagrid how can i handle it?
<DataGridTextColumn Binding="{Binding Path=SellingPrice, UpdateSourceTrigger=PropertyChanged}">
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="{x:Type TextBox}">
<Setter Property="MaxLength" Value="10"/>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
in above code i have given Value="10", I need to bind the value from ViewModel how can i do it

I'm not able to test this at the moment, but you may have to do this in your style:
<Style TargetType="{x:Type TextBox}">
<Setter Property="MaxLength" Value="{Binding Path=DataContext.MyMaxLength"/>
</Style>
Where MyMaxLength is a property on your bound object.

Related

WPF Set cell style for ALL DataGrid columns

Here's my problem. I work on an app that does some physics calculations, and I need to output all of the results as a datagrid. That would require more than 30 unique columns. In the old version of the app we just used DataGridTextColumn for that
<DataGridTextColumn Header="Section Type" Binding="{Binding SectionType}"/>
<DataGridTextColumn Header="Liquid Density, kg/m^3" Binding="{Binding LiquidDensity}"/>
...
But the problem is that I need to apply some styles to every cell, like make them non-focusable, centered etc. Here is the only solution I found.
<DataGrid.Resources>
<Style x:Key="NotFocusable" TargetType="{x:Type DataGridCell}">
<Setter Property="Focusable" Value="False"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Inlet Point" Binding="{Binding InletPoint}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Noto Sans"/>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource NotFocusable}"/>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
...
</DataGrid.Columns>
And that's a lot of code for just one column, given the fact that I need a few dozens of these. I feel like using 500+ lines of code just for one datagrid is a terrible way to do it.
Is it possible to somehow set the styles only once and then declare columns in one line, like in the first example, or at least use less lines of code for that?
you can define CellStyle once per DataGrid instead of doing it for columns. Setting ElementStyle can be shortened by declaring a resource and using attribute syntax with StaticResource extension:
<DataGrid.CellStyle>
<Style x:Key="NotFocusable" TargetType="{x:Type DataGridCell}">
<Setter Property="Focusable" Value="False"/>
</Style>
</DataGrid.CellStyle>
<DataGrid.Resources>
<Style x:Key="TextCell" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Noto Sans"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Inlet Point" Binding="{Binding InletPoint}" ElementStyle="{StaticResource TextCell}"/>
...
</DataGrid.Columns>

WPF DataGridTextColumn how to bind the Foreground color in a style based on the content of the cell

I have a DataGrid where I have the following
<DataGridTextColumn Header="MyHeader"
HeaderStyle="{StaticResource ServiceStatusColumn}"
ElementStyle="{StaticResource ServiceStatusElementStyle}"
Binding="{Binding PuServiceStatus, Converter={StaticResource serviceStatusText}}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource ServiceStatusCell}">
<Setter Property="Foreground" Value="{Binding PuServiceStatus, Converter={StaticResource serviceStatusColor}}" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
You can see that I have a style for the DataGridCell 'ServiceStatusCell'.
I would like to put the
<Setter Property="Foreground" Value="{Binding PuServiceStatus, Converter={StaticResource serviceStatusColor}}" />
As part of the definition of the ServiceStatusCell style, but I have not figured out how to do so. Presumably, I need some type of relative binding that gets to the content of the TextBlock ... but after much experimentation, I have been unable to do so
Here is the definition of ServiceStatusCell:
<Style x:Key="ServiceStatusCell" TargetType="DataGridCell">
<Setter Property="TextBlock.TextAlignment" Value="Center" />
<Setter Property="Width" Value="20"/>
<Setter Property="Height" Value="20"/>
</Style>
Any help would be greatly appreciated.
Putting the setter on the DataGridRow worked for me. This however changes the foreground for the entire row
<Style x:Key="RowProcessIdAndLevel" TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="Foreground" Value="{Binding Level, Converter={StaticResource LevelToForeground}}"/>
</Style>

CellStyle based on RowStyle in WPF

I have a WPF DataGrid represented in XAML. I'm using a RowStyle for my grid's TableView but also need to set some properties for specific cells. I need those cells to have the properties of the row style and apply the extra properties from the cell style on top of those.
What I would need is something like this, although this doesn't work as it's saying:
Target type 'CellContentPresenter' is not convertible to base type 'GridRowContent'
<Style x:Key="MyGridRowStyle"
BasedOn="{StaticResource {themes:GridRowThemeKey ResourceKey=RowStyle}}"
TargetType="{x:Type dxg:GridRowContent}">
<Setter Property="Height"
Value="25" />
<Style.Triggers>
...
</Style.Triggers>
</Style>
<Style x:Key="MyCellStyle"
BasedOn="{StaticResource MyGridRowStyle}"
TargetType="{x:Type dxg:CellContentPresenter}">
<Style.Triggers>
...
</Style.Triggers>
</Style>
I've also tried not specifying the BasedOn property for MyCellStyle but that doesn't work either.
I use the MyCellStyle like this:
<dxg:GridColumn Header="My Header"
FieldName="MyFieldName"
Width="100"
CellStyle="{StaticResource MyCellStyle}" />
and MyGridRowStyle like this on the TableView:
RowStyle="{StaticResource MyGridRowStyle}"
How can I make the cell style only change the properties specified in MyCellStyle and use the values specified in MyGridRowStyle for the other properties?
You can't base a CellContentPresenter style on a GridRowContent style. These are two completely different types and just because they may happen to have some properties that have the same name these are still completely different and independant properties with no relationship to each other.
The best thing you can do is to define the common values as separate resources and use these resources in both styles, e.g.:
<Window.Resources>
<s:Double x:Key="commonHeight">25</s:Double>
<SolidColorBrush x:Key="commonBg">Red</SolidColorBrush>
<Style x:Key="MyCellStyle" TargetType="{x:Type dxg:CellContentPresenter}">
<Setter Property="Height" Value="{StaticResource commonHeight}" />
<Setter Property="Background" Value="{StaticResource commonBg}" />
</Style>
<Style x:Key="MyGridRowStyle" BasedOn="{StaticResource {themes:GridRowThemeKey ResourceKey=RowStyle}}" TargetType="{x:Type dxg:GridRowContent}">
<Setter Property="Height" Value="{StaticResource commonHeight}" />
<Setter Property="Background" Value="{StaticResource commonBg}" />
</Style>
</Window.Resources>
But you still need to define all setters in both styles.
based on normal WPF DataGrid you could try this and expand it for dxg
the class DataGridCell is derived from ContentControl (that is a child from Content).
the class DataGridRow is derived from Control.
now you could try the following:
<Style x:Key="BaseStyle" TargetType="Control" >
<!-- Maybe add BaseStyle / theme here with BasedOn -->
<Setter Property="Height" Value="25" />
<!-- Row and Column defaults -->
</Style>
<Style x:Key="MyGridRowStyle" BasedOn="{StaticResource BaseStyle}"
TargetType="DataGridRow">
<!-- Row specific implementation -->
</Style>
<Style x:Key="MyCellStyle" BasedOn="{StaticResource BaseStyle}"
TargetType="DataGridCell">
<!-- Column specific implementation -->
</Style>
summary:
use base type of both Row and Column classes for your BaseStyle and use this one as BasedOn. For dxg you can extend it by your own...
My understanding of the question: values of the cell style should change based off of values in the style of the row it is in.
Trigger off of value
Here is a simple working example (test it by changing the DataGridRow Background to Red, you will notice that the cell's foreground changes to Blue):
<DataGrid>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="White"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow, Mode=FindAncestor}, Path=Background}" Value="Red">
<Setter Property="Foreground" Value="Blue"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
You can do a similar binding to directly set properties of the CellStyle to the value of properties of the row it is in.
Relative bind directly to a property
<DataGrid x:Name="dataGrid1" ItemsSource="{Binding Collection}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Height" Value="20"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="FontSize" Value="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow, Mode=FindAncestor}, Path=Height}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Explanation
RelativeBinding works due to the fact that DataGridCells are eventual children of DataGridRows as can been seen in this screenshot of the visual tree of a DataGrid:

WPF:Using checkbox IsChecked property in DataTrigger

I am trying to use WPF checkbox's IsChecked property in a DataTrigger.Based on the value i am setting particular DataGridRow's background.
My NOT WORKING code
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="LightGray" />
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=chkbox, Path=IsChecked}" Value="true">
<Setter Property="Background" Value="LightCyan" />
</DataTrigger>
</Style.Triggers>
</Style>
<DataGrid x:Name="dataGrid1" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn MinWidth="40" Width="Auto" Header="Select">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chkbox" IsChecked="{Binding Selected, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Then I checked this link and changed the code as below and it is working fine.Here Selected is my public property.
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="LightGray" />
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Selected}" Value="true">
<Setter Property="Background" Value="LightCyan" />
</DataTrigger>
</Style.Triggers>
</Style>
Please help me to understand why my original code is not working? am i missing anything.
google did not help.surprisingly there is no thread for this on SO also! Thank you for the help.
The original code is not working because you're trying to locate an object via ElementName which exists as a templated object, and thus isn't created until after the binding tries to resolve. Generally, you should only use ElementName when referring to ancestor objects in the visual tree, and not to children, particularly templated children.
As mentioned in comments, it would also not be possible to use a {RelativeSource FindAncestor... binding here because the CheckBox is a child, not an ancestor, of the DataGridRow

How to control the whole DataGridCell background and not just the text part?

I'm trying to control the DataGrid cell background in a column conditionally on its value. Unfortunately I'm getting something like this:
Which is not very aesthetic, I would like to have the whole cell in a different colour, not only the part behind the text. Here is the code part:
<DataGridTextColumn
Binding="{Binding Path=PrivateMemorySize, StringFormat='#,##0'}"
Header="Memory Size" >
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=PrivateMemorySize,
Converter={StaticResource isLarge},
ConverterParameter=20000000}" Value="true">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
(isLarge is just a converter that returns true when the cell value is greater than the parameter)
If I define a style for the DataGridCell target, the result is the same.
Any idea on what could be wrong? I'm not using anything fancy, just the default DataGrid (which is linked in this example to CLR objects to fill in the table).
In the style for your TextBlock, set the HorizontalAlignment to Stretch, and Set the TextAignment to Right:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="TextAlignment" Value="Right" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=PrivateMemorySize,
Converter={StaticResource isLarge},
ConverterParameter=20000000}" Value="true">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>

Categories