I've tried many options, but none seem to work fine for me. Here is the problem:
Dynamic columns. I get a list of dictionaries. All dictionaries may have different keys.
E.g.
[ [key1: 111], [key2: 222] ]
[ [key1: 333], [key4: 444] ]
[ [key5: 777] ]
I need to display a grid with all keys as columns like this:
[key1] [key2] [key4] [key5]
111 222
333 444
777
This is pretty easy, I just generate columns in code either for GridView or DataGrid.
But there is a second requirement:
I need to color particular cells depending on value in them.
E.g. for 111 bg color should be green, for 333 it should be red etc.
Currently I can only make one part work. I can dynamically create columns, but then I can't color them. Or I can create static columns and create custom cell templates with bindings for bg colors. But, then in every template I have to specify the binding. So the number of templates will be big.
Is there a way to achive what I need, without generating template for each column?
Personally I would like to avoid generating templates in code.
Not sure I understand your problem completely, but it should be quite simple. DataGrid is amazingly flexible.
You almost have it, as far I understand. Now you want one global CellTemplate that can be obtained from XAML resources(so you don't hardcode it into code).
The CellTemplate can change colors based on triggers. You can either hardcode it into XAML or provide Dictionary that can map from "VALUE" to "COLOR" and just bind CellTemplate's Background to that Dictionary.
When you generate dynamically columns, you set DataGridTextColumn.CellTemplate to LoadDynamicallyXaml("yourresource"). When you generate columns, you have access to your DataGrid Resources, and you can obtain the CellTemplate from there too, that's cleaner way.
Loading XAML at runtime?
You can define a Style for a TextBlock that contains your DataTriggers and then just apply that Style to a TextBlock in your dynamically created columns... this method should be good for up to around 8 different value/colour pairs before the code gets too long:
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="111">
<Setter Property="TextElement.Foreground" Value="LightGreen" />
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="222">
<Setter Property="TextElement.Foreground" Value="LightBlue" />
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="333">
<Setter Property="TextElement.Foreground" Value="LightPink" />
</DataTrigger>
</Style.Triggers>
</Style>
The other method that you can use is to use a Converter class with your Binding. You can find a detailed example of doing this in many online posts... here are a few:
How to set Foreground of DataGrid Column with ValueConverter
Datagrid AutoGenerateColumns="True" forecolor IValueConverter
Related
This question already has answers here:
WPF Style DataTrigger with binding to DataContext not working
(1 answer)
Trigger based on text property not working
(1 answer)
Closed 2 years ago.
I am trying to make customizable DataGrid. I have a problem. I have researched but i couldn't find anything about it.
I created a Style for cells. In this style, there is an MultiTrigger like in the code below.
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsKeyboardFocusWithin}" Value="True"/>
<Condition Binding="{Binding DataContext.Tek_Satiri_Guncelleme_Modu, RelativeSource={RelativeSource AncestorType={x:Type local:DataGrid_Ozellestirilebilir}}}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="BorderBrush" Value="Blue"/>
</MultiDataTrigger>
This Multitrigger works perfectly as expected like this;
This is static state -->
When cell is in focused-->
Then in C#, I change the color of cell like this.
//Get row
DataGridRow dataGridRow = (DataGridRow)DataGrid_1.ItemContainerGenerator.ContainerFromIndex(5);
//Get cell
DataGridCell cell = (DataGridCell)DataGrid_1.Columns[5].GetCellContent(dataGridRow).Parent;
cell.BorderBrush = Brushes.White; //This color i see when cell is in focus.
When i run the application this code overrides (i guess) my custom Style and i cant see Blue when the cell is in focus. I see White.
Border color turned to white as expected-->
This what i should see when cell is in focus. But i see white instead.-->
Can anyone help me about this situation?
Edit:
thatguy made very good explanation about this situation and gave two solutions. But there is a problem. This solutions work for only one color. So if I want to change the color of more than one cell, they must all be the same color. I need to adjust the colors of different cells differently. Is there any solution for this situation too?
This is caused by the precedence of a local value over a Style trigger, see the documentation.
Local value. A local value might be set through the convenience of the "wrapper" property, which also equates to setting as an attribute or property element in XAML, [...]
Style triggers. The triggers within styles from page or application (these styles might be either explicit or implicit styles, but not from the default styles, which have lower precedence).
To solve this problem, you could use one of the following options.
Try to integrate the White color with additional triggers into your existing style
Create another style based on your current style and add a setter for the color White and assign this style to the cells that need to be styled differently
<Style x:Key="MySpecialCellStyle" BasedOn="{StaticResource MyCellStyle}" TargetType="{x:Type DataGridCell}">
<Setter Property="BorderBrush" Value="White"/>
</Style>
cell.Style = (Style)FindResource("MySpecialCellStyle");
I have this XAML in my RadDataGrid that changes the background color of a selected row to red based on the value returned by the ValidateModuleBank property defined in my model.
<tg:RadDataGrid.Resources>
<Style TargetType="gridPrimitives:SelectionRegionBackgroundControl">
<Setter Property="Background" Value="{Binding ValidateModuleBank,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Style>
</tg:RadDataGrid.Resources>
I looked online and it says that UWP does not support binding to a property in a style. So, how can I achieve this?
Thanks in advance for your help.
The basics of binding a list of objects to a DataGrid are discussed here How do I bind a List<CustomObject> to a WPF DataGrid?.
My setup is slightly more complex:
I have RowModels which contain metadata for the row as well as a list of CellModels. The CellModels again contain some metadata and a Value property which is shown in the dataGrid.
To fill my DataGrid I did set
ItemsSource="{Binding RowModelList, UpdateSourceTrigger= PropertyChanged}"
and mapped the columns one-by-one via
<DataGridTextColumn Binding="{Binding CellModelList[0].Value, UpdateSourceTrigger= PropertyChanged}"/>
<DataGridTextColumn Binding="{Binding CellModelList[1].Value, UpdateSourceTrigger= PropertyChanged}"/>
...
This way i could also specify a ColumnHeader for each column and modify the presentation of each column.
However i would like to also use a DataTrigger in my DataGridCell-Style to access the metadata of my CellModels.
this works, but.. well:
Of course I could create a Style for each column like
<Style x:Key="CellStyleColumnZero" TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding CellModelList[0].Enabled}" Value="False">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
Question:
I need to set Properties of the DataGridCell depending on the metadata in my CellModel.
I am sure there is a more elegant solution (than the one shown above) which doesn't require customizing every single column. I still need to be able to manually change single columns (especially the ColumnHeaders) which is why i manually declared the DataGridTextColumns one-by-one in the first place.
Do you have any suggestions how to approach this properly?
This was answered in a followup question.
The solution i used was creating an attached property for DataGridCell in which i store the CellModel and access the properties from there.
See the linked question for code:
Structure of WPF DataGrid - change cells depending on value
I'm writing an IM program on Windows Phone 8. And I am currently dealing with the UI for chatting.
I want to create a ListBox that holds all the "chat bubbles" (like those in iPhone). The incoming messages appear on the left-hand side, and outgoing messages on the right-hand side. Like this:
So obviously, I need to set differnt alignment for each item.
I was trying to solve this by wrapping the bubble in a large Grid that expands all the space in the ItemsPanel, and align the chat bubble to the right (the parent of the chat bubble is the large Grid). But that didn't work because a grid in ItemsPanel won't fill up all the spaces automatically. And then I went for searching "how to fill up all spaces in ItemsPanel" and no luck.
So, I think the only way to do this is to set different ItemsPanelTemplate for each ItemsPanel, to either "Right" or "Left".
Please, help me.. Thank you!
So how do you create a selector for different ItemsPanelTemplate?
You just need to customize the itemContainer :
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Style.Triggers>
<DataTrigger Binding="{Binding IsAnswer}" Value="True">
<Setter Property="HorizontalAlignment" Value="Right"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
In case you dont have style triggers, you can use binding and a bool to HorizontalAlignment converter :
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="HorizontalAlignment" Value="{Binding IsAnswer,Converter={StaticResource AlignmentConverter}}"/>
</Style>
</ItemsControl.ItemContainerStyle>
you only need 2 View's for your messages aka DataTemplate
one for MyMsg and one for Answer both inhire from the Message class or interface (your decision) lets call it Msg
so you can set your ItemsSource to List<Msg> or ObservableCollection<Msg> and you are done
Firstly let me clarify (if the title wasn't clear enough): I'm discussing System.Windows.Controls.DataGrid from the .NET 4.0 Framework, not the toolkit edition.
I have a data grid which i read in from a csv which can change with every load.
I am trying to create a simple search, I have been trying to use;
http://www.codeproject.com/KB/WPF/FirefoxLikeSearchWithMVVM.aspx
http://manfred-ramoser.blogspot.com/2009/11/search-highlighting-in-wpf-datagrid.html
and others, but there all seem very complicated for a simple task, can anyone help, just to be clear a filtering system is not want i am after, thank you.
For my project i did a search function this way :
i added a 'FilterResult' Boolean property to the ViewModel of my data. It is implementing NotifyPropertyChanged.
So i perform the filter on my list of object with simple foreach loop and i set/unset FilterResult
And in the 'Style' of the DataGridRow i put a Setter on Visibility depending upon this FilterResult
<Style TargetType="{x:Type DataGridRow}" x:Key="EventColorRowStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding FilterResult}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
This simpler and much faster than using the Filter of a CollectionView, but still i can point you on what msdn says about it : http://msdn.microsoft.com/en-us/library/ff407126.aspx