Setting styles for DataGrid Columns - c#

I have a DataGrid where I'm trying to set the background of each element depending on what text is being displayed in that grid cell. The grid cells are defined as follows and accessing them works correctly:
<Window.Resources>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="MouseDown" Handler="Clicked" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
The part that doesn't work is that I can't set the a style for the DataGridTextColumn, none of my setters below are doing anything. The DataGrid itself is being displayed corrrectly.
<DataGrid Name="dataGrid1" AutoGenerateColumns="False" IsReadOnly="true">
<DataGridTextColumn>
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="Text" Value="None">
<Setter Property="Background" Value="Aquamarine"/>
</Trigger>
<Trigger Property="Text" Value="First">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid>
Thanks in advance for any help.
EDIT 1
Updated with Answers to NETscape's questions.
1) My DataGrid is showing correctly, I'm even clicking on items in the grid and modifying the data behind it. However, I don't have a DataSource set in my XAML, just a simple DataContext in my view that points to the DataGrid.
2) I don't think that the problem is with my variable names since the setter property below that doesn't have a trigger also isn't showing:
<Setter Property="HorizontalAlignment" Value="Center" />
EDIT 2
Again in response to NETscape's questions/comments. I didn't post my code-behind originally because, since all my objects were displaying correctly, I wasn't looking for the problem there. But I think I was mistaken. The data binding for my grid and for the columns in the grid are different. The DataContext for my grid is an array of RowObjects. The datacontext for each DataGridTextColumn is one entry in my RowObject tied to a particular day of the week.
DataGridTextColumn cSunday = new DataGridTextColumn();
DataGridTextColumn cMonday = new DataGridTextColumn();
public TimeSlice[] TimeArray = new TimeSlice[48];
MyWnd.dataGrid1.DataContext = TimeArray; //sets DataContext for the DataGrid
CultureInfo cu = new CultureInfo(App.CultureID);
//creates one column
cSunday.Header = cu.DateTimeFormat.GetDayName(DayOfWeek.Sunday);
cSunday.Binding = new Binding("StatusSunday");
Wnd.dataGrid1.Columns.Add(cSunday);
cMonday.Header = cu.DateTimeFormat.GetDayName(DayOfWeek.Monday);
cMonday.Binding = new Binding("StatusMonday");
Wnd.dataGrid1.Columns.Add(cMonday);
EDIT 3
For completeness sake, adding the working solution derived fron NETscape's answer. XAML:
<Window
<Window.Resources>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="MouseDown" Handler="Clicked" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="MyDataGridTextColumnElementStyle"
TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="Text" Value="None">
<Setter Property="Background" Value="Aquamarine"/>
</Trigger>
<Trigger Property="Text" Value="First">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Name="MainView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row ="0">
</Border>
<Border Grid.Row="1">
<DataGrid Name="dataGrid1" AutoGenerateColumns="False" IsReadOnly="true"/>
</Border>
</Grid>
</Window>
And the code in my view model for setting up the first 2 days/columns:
public TimeSlice[] TimeArray = new TimeSlice[48];
public ViewModelr(WndCalendar Wnd)
{
MyWnd = Wnd;
MyWnd.DataContext = this;
MyWnd.dataGrid1.DataContext = TimeArray;
cTime.Header = "";
cTime.Binding = new Binding("TimeofDay");
Wnd.dataGrid1.Columns.Add(cTime);
CultureInfo cu = new CultureInfo(App.CultureID);
cSunday.Header = cu.DateTimeFormat.GetDayName(DayOfWeek.Sunday);
cSunday.Binding = new Binding("StatusSunday");
Wnd.dataGrid1.Columns.Add(cSunday);
cSunday.ElementStyle = MyWnd.FindResource("MyDataGridTextColumnElementStyle") as Style;
cMonday.Header = cu.DateTimeFormat.GetDayName(DayOfWeek.Monday);
cMonday.Binding = new Binding("StatusMonday");
Wnd.dataGrid1.Columns.Add(cMonday);
cMonday.ElementStyle = MyWnd.FindResource("MyDataGridTextColumnElementStyle") as Style;

Frank E, your Edit 2 might have given away your issue; it's always helpful to know when you're doing things programmatically!
Setting the Style inside of Windows.Resources is saying, "hey, for any DataGridCell in this control, apply this style to it." That is why it's working properly, because after all the information is added, the styles still get applied; which is why it seems to be working.
Now notice you are defining a DataGridTextColumn and it's ElementStyle. That isn't being applied to all the DataGridTextColumn's which may be what you were thinking. Instead, that is being applied to that single DataGridTextColumn! Because you're not defining anything for that DataGridTextColumn it's actually being drawn in the DataGrid, but since there is no content for that column, it's Width = 0.
Since you're creating the other columns programmatically, you need to apply the Style programmatically. So you should have something like this:
<Window.Resources>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="MouseDown" Handler="Clicked" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="MyDataGridTextColumnElementStyle"
TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="Text" Value="None">
<Setter Property="Background" Value="Aquamarine"/>
</Trigger>
<Trigger Property="Text" Value="First">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Then when you're creating your columns in code behind, do something like this:
cSunday.ElementStyle = MyWnd.FindResource("MyDataGridTextColumnElementStyle") as Style;
for each column that you are creating.
From what I understand, not assigning a x:Key will apply the style to all elements that are of type TargetType, so since we assign a x:Key to the 2nd style, not all TextBlock will be assigned that style, only the ones we specify.
Let me know if this helps.

Related

How to change datagridrow backcolor based on "IsSelected" property?

I'm struggling to get the colors of a datagridrow to change colors based on row "IsSelected" property. I have looked at all examples and tried all the best I can but still can't get it to work. Well, actually it works on initial startup of the application, but when I change the datagrid's "SelectedIndex", the selected index row get's highlighted as if it's selected but the colors revert to default and don't change.
The user cannot interact with this grid. Everything is done in code-behind, including the number of rows it has and which row "IsSelected" in the DataGrid. I have the "SelectedIndex" property of the Datagrid bound to a property value in code behind. As noted, setting and changing that property works fine and the row of the DataGrid highlights fine as I change the "SelectedIndex" property. But the background and foreground colors of the row don't change appropriately.
I have created a rowstyle for the Datagrid's rows as follows:
<Style x:Key="RowStyle3" TargetType= "{x:Type DataGridRow}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="IsHitTestVisible" Value="False"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="#FF232E3C"/>
<Setter Property="Foreground" Value="#FFC8E5FF"/>
</Trigger>
</Style.Triggers>
</Style>
The "SelectedIndex" property gets set by another external application. It works fine. That is how I am changing which row IsSelected.
With "SelectedIndex" set to '1', and then initial start of the application, it works fine and here is what the grid looks like, which is what I need.
Now, with the application open and then change the "SelectedIndex" of the DataGrid to '2', I expect the the third row in the grid to change color to red, but this is what I get instead:
It highlights the row index fine, but the colors didn't change like I expect.
Here is the XAML that defines the DataGrid. I'm setting the size of the rows and columns as well as the data (datatable) in code-behind when the app starts.
<DataGrid x:Name="DG_TestRuntime"
HorizontalAlignment="Left" Height="695.936" VerticalAlignment="Top" Width="1223.789"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"
ColumnHeaderHeight="48" ColumnHeaderStyle="{DynamicResource DGCHeaderStyle}"
CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserSortColumns="False"
SelectionMode="Single" CanUserResizeRows="False"
HorizontalGridLinesBrush="#FF688CAF" VerticalGridLinesBrush="#FF688CAF"
HeadersVisibility="Column" CanUserAddRows="False"
HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled"
IsEnabled="True" Background="#FF232E3C" Foreground="#FFC8E5FF"
SelectedIndex="{Binding StepNumber, Mode=OneWay, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True}"
RowStyle="{DynamicResource RowStyle3}">
<DataGrid.DataContext>
<local:MyProperties/>
</DataGrid.DataContext>
</DataGrid>
I am grateful for any guidance. Thank you.
Set not only DataGridRow but also DataGridCell
<Style TargetType= "{x:Type DataGridRow}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="IsHitTestVisible" Value="False"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="#FF232E3C"/>
<Setter Property="Foreground" Value="#FFC8E5FF"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType= "{x:Type DataGridCell}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="IsHitTestVisible" Value="False"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="#FFC8E5FF"/>
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>

How to change font color of selected row in datagrid WPF C# when using context menu

I am developing a WPF Application using Mahapps.Metro library.
There is a DataGrid where I want to use a ContextMenu on the added rows, for that I am defining this in datagrid resources
<DataGrid.Resources>
<ContextMenu x:Key="RowMenu"
DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Borrar detalle" Click="delete_Click" />
<MenuItem Header="Editar detalle" Click="edit_Click" />
</ContextMenu>
</DataGrid.Resources>
and adding that context menu in the rowstyle
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" >
<Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
</Style>
</DataGrid.RowStyle>
The problem with this is that when user clicks on the row, it seems to disappear (the font color turns white).
I tried adding the following to the rowstyle but it does not seems to work.
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" >
<Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="LightSkyBlue"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="LightSkyBlue"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="Transparent"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
MY last option is to use the contextmenu in the grid instead rows, but I want to know if there is something I can do to make this work.
Hope you can help, thanks.
You should use based-on feature on your defined style:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
</Style>
</DataGrid.RowStyle>

WPF TreeView - Apply styling based on enum value

I have a TreeView bound to an ObservableCollection containing enum values:
public enum Categories
{
CatA, CatB, CatC, CatD
}
public ObservableCollection<Categories> CategoriesList = new ObservableCollection<Categories>();
foreach (Categories cat in (Categories[])Enum.GetValues(typeof(Categories)))
{
CategoriesList.Add(cat);
}
The TreeView is bound to CategoriesList:
tvCat.ItemsSource = CategoriesList;
The the XAML markup:
<TreeView x:Name="tvCat">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
I am trying to figure out how to apply individual stying to TreeViewItem for each enum value, e.g. blue color for CatA, red color for CatB, may be an icon for CatC etc.
Thanks a lot for any help.
You can use DataTriggers to get the desired output.
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<DataTrigger Binding="{Binding}" Value="CatA">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="CatB">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
EDIT
The above XAML is if you just want a different color for your Items. If you also want to have different content (e.g. an icon for CatC), then you'd have to set the ControlTemplate based on a DataTrigger.
Here is the XAML to achieve that.
<TreeView.Resources>
<ControlTemplate TargetType="TreeViewItem" x:Key="CatCTemplate">
<Image Source="icon.jpeg" Height="64" Width="64" />
</ControlTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<DataTrigger Binding="{Binding}" Value="CatA">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="CatB">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="CatC">
<Setter Property="Template" Value="{StaticResource CatCTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>

WPF :Material Design + dragablz tabItem header style

I am working in WPF with the MaterialDesign Toolkit and Dragablz.
I encountered a problem while trying to style a TabablzControl.
I already have style for the windows default TabControl and TabItem header, as shown in the picture:
http://i.imgur.com/2anl5rl.png
But when I change the default tabControl to TabablzControl, it turns into this:
http://i.imgur.com/bhaaMVy.png
Here are the window.resources:
<Style x:Key="mdTabControl" TargetType="TabControl">
<Setter Property="TextElement.Foreground" Value="{DynamicResource MaterialDesignBody}"/>
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}"></Setter>
</Style>
<Style x:Key="mdTabHeader" TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}"></Setter>
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border" Margin="1,0,1,0" CornerRadius="3 3 0 0">
<ContentPresenter x:Name="ContentSite" VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header" Margin="10,2,10,2"
RecognizesAccessKey="True">
</ContentPresenter>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="Background" Value="{StaticResource SecondaryAccentBrush}" />
<Setter Property="Foreground" Value="{StaticResource SecondaryAccentForegroundBrush}"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryHueMidBrush}" />
<Setter Property="Foreground" Value="{StaticResource PrimaryHueMidForegroundBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryHueDarkBrush}" />
<Setter Property="Foreground" Value="{StaticResource PrimaryHueDarkForegroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The error appears when I change the mdTabControl style targetType to:
TargetType="dbz:TabablzControl"
I want to keep the style I set to the TabControl, but with the added functionality of the TabablzControl
Any help will be appreciated
First thing to note, which is a general WPF characteristic, you are not using style inheritance correctly.
As you are using Material Design with Dragablz, if you are restyling the tab control itself, you must inherit from the Material Design style in the Dragablz assembly using BasedOn:
<Style x:Key="mdTabControl" TargetType="TabControl" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}">
<Setter Property="TextElement.Foreground" Value="{DynamicResource MaterialDesignBody}"/>
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}"></Setter>
</Style>
Again, with the tab header itself, you need to inherit from the relevant style:
<Style x:Key="mdTabHeader" TargetType="{x:Type TabItem}" BasedOn="{StaticResource MaterialDesignDragableTabItemStyle}">
. . .
</Style>
Note, that (depending you your App.xaml setup) you probably need to make sure the correct resource dictionary is included in the same XAML file. For example a more complete XAML might be:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="NormalTabItemStyle" TargetType="{x:Type dragablz:DragablzItem}" BasedOn="{StaticResource MaterialDesignDragableTabItemStyle}">
<Setter Property="Width" Value="280" />
<Setter Property="Padding" Value="1" />
</Style>
. . .
</ResourceDictionary>
</Window.Resources>
Finally, as you are changing the TabItem style, you either need to the TabablzCOntrol style the correct style, or you could use it where you actually declare the TabablzControl itself:
<dragablz:TabablzControl ItemContainerStyle="{StaticResource mdTabHeader}" />
A good example of all this in action is in the SidePanels project in the demo solution at: https://github.com/ButchersBoy/DragablzSamplez
<Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}"/>

Change the color of a grid header using Xceed Datagrid in WPF

I am using the Xceed data grid control and I am trying to change the header colors, but seem to be having some trouble. What I have right now is the following code snippet:
Style style = new Style(typeof(ColumnManagerRow));
style.Setters.Add(new Setter(ColumnManagerRow.BackgroundProperty, Brushes.Black));
this.grid.Resources[typeof(ColumnManagerRow)] = style;
This works for the most part, but I am still seeing some gray around it. Any help would be greatly appreciated.
EDIT
I've added an image with the selected areas that I'd like to have as the same color.
You could do this in XAML:
<ControlTemplate x:Key="HeaderTemplate" TargetType="{x:Type xcdg:ColumnManagerCell}">
<TextBlock Text="{TemplateBinding Content}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="Black" />
<Setter Property="Foreground" Value="Red" />
</Style>
</TextBlock.Style>
</TextBlock>
</ControlTemplate>
<Style TargetType="{x:Type xcdg:ColumnManagerRow}">
<Setter Property="Background" Value="Black"/>
<Setter Property="BorderBrush" Value="Black"/>
</Style>
<Style TargetType="{x:Type xcdg:ColumnManagerCell}">
<Setter Property="Template" Value="{StaticResource HeaderTemplate}"/>
</Style>

Categories

Resources