data trigger with enum - wpf

I have an Enum:
namespace LibiqCommonStructures
{
using System;
public enum ItemStatusType
{
NotImplemented,
New,
Processed,
Missing,
NotUsed,
Failed
}
}
<igWPF:XamDataGrid DataSource="{Binding Path=Images}" ActiveDataItem="{Binding SelectedItem}" MaxHeight="300">
<igWPF:XamDataGrid.Resources>
<Style TargetType="{x:Type igWPF:DataRecordCellArea}" BasedOn="{StaticResource {x:Type igWPF:DataRecordCellArea}}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Record.DataItem.ItemStatus}" Value="{x:Static libIq:ItemStatusType.Missing}">
<Setter Property="Background" Value="Tomato"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</igWPF:XamDataGrid.Resources>
<igWPF:XamDataGrid.FieldLayoutSettings>
<igWPF:FieldLayoutSettings SelectionTypeRecord="Single" AutoGenerateFields="False" AllowDelete="False"/>
</igWPF:XamDataGrid.FieldLayoutSettings>
<igWPF:XamDataGrid.FieldSettings >
<igWPF:FieldSettings Width="Auto" AllowEdit="False" />
</igWPF:XamDataGrid.FieldSettings>
<igWPF:XamDataGrid.FieldLayouts>
I want to change the background color of the row when the enum is ItemStatusType.Missing
i can see missing the in the binding but the color of the row doesn't change.
maybe something is wrong with my x:static?

Just put the enum string in the Value. It will work:
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Record.DataItem.ItemStatus}" Value="Missing">
<Setter Property="Background" Value="Tomato"></Setter>
</DataTrigger>

Related

WPF: unique style for each combo box item bound to dictionary

A ComboBox bound to the dictionary (of Enum, String). Selected value path is dictionary's Key.
Is it possible to set individual style for each combo box item in XAML?
In the following I use a custom enum called Cards, that has constants Skull, Hearts and others for demonstration purposes. You can simply use your enum type instead.
Item Container Style Using Data Triggers
You could create an items container style with triggers for each enum value.
<Style x:Key="EnumComboBoxItemStyle" TargetType="{x:Type ComboBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Key}" Value="{x:Static local:Cards.Skull}">
<Setter Property="Foreground" Value="Blue"/>
</DataTrigger>
<DataTrigger Binding="{Binding Key}" Value="{x:Static local:Cards.Hearts}">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
<ComboBox ItemContainerStyle="{StaticResource EnumComboBoxItemStyle}" ...>
Item Container Style Selector
Another option is to create a style selector if you have multiple distinct styles like this:
<Style x:Key="SkullComboBoxItemStyle" TargetType="{x:Type ComboBoxItem}">
<Setter Property="Foreground" Value="Green"/>
</Style>
<Style x:Key="HeartsComboBoxItemStyle" TargetType="{x:Type ComboBoxItem}">
<Setter Property="Foreground" Value="Red"/>
</Style>
<!-- ...other styles. -->
The style selector determines the style based on the enum value.
public class CardsKeyStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
if (container is FrameworkElement element && item is KeyValuePair<Cards, string> keyValuePair)
{
switch (keyValuePair.Key)
{
case Cards.Skull:
return element.FindResource("SkullComboBoxItemStyle") as Style;
case Cards.Hearts:
return element.FindResource("HeartsComboBoxItemStyle") as Style;
// ...other cases.
}
}
return null;
}
}
You can assign the style selector to your combo box and it will choose the right style.
<ComboBox ...>
<ComboBox.ItemContainerStyleSelector>
<local:CardsKeyStyleSelector/>
</ComboBox.ItemContainerStyleSelector>
</ComboBox>
My solution is further. First, define enumerable type and dictionary, associated with it:
Public Enum MyEnum As Integer
OneValue = 0
OtherValue = 1
End Enum
Public ReadOnly Property MyDict As Dictionary(Of MyEnum, String)
Get
Return New Dictionary(Of MyEnum, String) From {
{MyEnum.OneValue, "First value text"},
{MyEnum.OtherValue, "Other value text"}
}
End Get
End Property
Next, in XAML use it in this manner:
<Style TargetType="Ellipse" x:Key="ellipseStyle">
<Setter Property="Height" Value="10" />
<Setter Property="Width" Value="10" />
<Style.Triggers>
<DataTrigger Binding="{Binding Key}" Value="0"><!-- "0" - one of the dictionary key -->
<Setter Property="Fill" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding Key}" Value="1"><!-- "1" - one of the dictionary key -->
<Setter Property="Fill" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type ComboBox}" x:Key="cmb_osn_rez">
<Setter Property="ItemsSource" Value="{Binding MyDict}" />
<Setter Property="SelectedValuePath" Value="Key" />
<Setter Property="ItemsControl.ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Style="{StaticResource ellipseStyle}" />
<TextBlock Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>

Uisnga DataTrigger to hide xceed data grid rows

I am working on WPF MVVM project and I have a ObservableCollection with class that contains a boolean property and a string property. That Observablecollection is bound xceedwpfgrid. I am trying to add a datatrigger that checks the boolean and based on that property shows or hides the row. I tried a few things but im not able to hit the datatrigger on the xceedgrid can someone help me.
<TreeGrid:XceedColumnBindingGrid ItemsSource="{Binding Path=.DataList}"
AutoCreateColumns="False"
IsTabStop="False"
SelectedItem="{Binding Path=.SelectedItem}"
ContextMenuBuilder="{Binding Path=.ContextMenuBuilder}">
<TreeGrid:XceedColumnBindingGrid.Resources>
<Style TargetType="{x:Type DataGridRow}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=.DataList.IsOnExclusionList}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=.DataList.IsOnExclusionList}" Value="false">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeGrid:XceedColumnBindingGrid.Resources>
<TreeGrid:XceedColumnBindingGrid.Columns>
<xcdg:Column FieldName="IsOnExclusionList" Title="IsOnExclusionList" Width="30" CellContentTemplate="{StaticResource cellCashDeliveringTemplate}" CellEditorDisplayConditions="None"/>
<xcdg:Column FieldName="Name" Title="Name" Width="30" CellContentTemplate="{StaticResource cellCashDeliveringTemplate}" CellEditorDisplayConditions="None"/>
</TreeGrid:XceedColumnBindingGrid.Columns>
</TreeGrid:XceedColumnBindingGrid>
I am hoping that the datatrigger will show and hide the row depnding on the boolean variable

WPF Datagrid clipboard get cell value

I need to handle the Ctrl+C function in my datagrid, especially I need to get the cell of a selected value. Here's the XAML code of the datagrid. Please note that I use DataGridTextColumn
<DataGrid x:Name="GridFormule" Grid.Row="0" BorderBrush="#abadb3" CanUserSortColumns="true" Sorting="GridFormule_Sorting" MaxColumnWidth="Infinity" Style="{DynamicResource DataGridStyle}" ColumnHeaderStyle="{DynamicResource DataGridColumnHeaderStyle}" ItemsSource="{Binding ElementName=ObjectsTree, Path=SelectedItem.Infos}" CellEditEnding="GridFormule_CellEditEnding" Margin="8,5,2,0" ContextMenu="{StaticResource cntextListe}">
<!-- OVERRIDE COPY CONTROL -->
<DataGrid.InputBindings>
<KeyBinding Key="C" Modifiers="Control" Command="Copy" />
</DataGrid.InputBindings>
<DataGrid.CommandBindings>
<CommandBinding Command="Copy" Executed="Comandi_Executed" />
</DataGrid.CommandBindings>
<!-- /OVERRIDE COPY CONTROL -->
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Field.Formula.Formula, Mode=TwoWay}" Header="#_57_Formule" Foreground="Black" Width="*" ClipboardContentBinding="{Binding Field.Formula.Formula, Mode=TwoWay}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Padding" Value="4" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="11.55" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsDirty}" Value="True">
<Setter Property="TextBlock.Background" Value="{StaticResource IsDirtyColor}" />
<Setter Property="Padding" Value="4" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="Background" Value="White"></Setter>
<Setter Property="Padding" Value="2,4,2,3"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
The code behind to handle the copy:
private void Comandi_Executed(object sender, ExecutedRoutedEventArgs e)
{
RoutedUICommand c = (RoutedUICommand)e.Command;
switch (c.Name)
{
// Copia
case "Copy":
DataGrid sel = (sender as DataGrid);
if (sel == null) return;
if (sel.CurrentItem != null) return;
var cc = sel.CurrentColumn;
Binding binding = (Binding)cc;
// Here I get the property Name!
string BoundPropName = binding.Path.Path;
try
{
//Clipboard.SetDataObject(text);
}
catch (Exception ex)
{
Global.LOG.Log(ex.Message);
}
break;
}
}
Basically my BoundPropName returns "Field.Formula.Formula" instead of the value visible in the cell of datagrid. How can I get the cell value?

WPF - DataGrid column binding to attached property not working on context menu

I have ToggleButtons and a DataGrid, each row in DataGridColumn has a ColGroup AttachedProperty set to the name of the column group name.
Attached property:
public class DataGridColumnsGroupProperty {
public static readonly DependencyProperty ColGroupProperty =
DependencyProperty.RegisterAttached("ColGroup", typeof(object), typeof(DataGridColumnsGroupProperty), new FrameworkPropertyMetadata(null));
public static void SetColGroup(DependencyObject element, string value) {
element.SetValue(ColGroupProperty, value);
}
public static string GetColGroup(DependencyObject element) {
return (string)element.GetValue(ColGroupProperty);
}
}
The ToggleButtons has two jobs, on Check/UnCheck show/collapse all columns with the same group name.
and it has a ContextMenu which shows only the DataGridColumns with the same group name.
I've managed to bind all DataGridColumns to the ToggleButton, but couldn't find a way to Collapse the DataGridColumns with different group names.
How to fill context menu with only the columns with the givin group name inside the Style Trigger?
And how to hid all columns that has the group name when un-check toggle button?
XAML:
<ToggleButton.ContextMenu>
<ContextMenu x:Name="ContextMenu" ItemsSource="{Binding Columns, ElementName=ElementDataGrid, Converter={StaticResource TestConverter}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="HeaderTemplate" Value="{Binding HeaderTemplate}"/>
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="StaysOpenOnClick" Value="True" />
<Setter Property="AutomationProperties.Name" Value="{Binding Header}"/>
<Setter Property="IsCheckable" Value="True" />
<Setter Property="IsChecked" Value="{Binding Visibility, Mode=TwoWay, Converter={StaticResource VisibilityToBooleanConverter}}" />
<Style.Triggers>
<Trigger Property="attachedProperties:DataGridColumnsGroupProperty.ColGroup" Value="FirstGroup">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</ToggleButton.ContextMenu>
DataGridColumns:
<DataGridTextColumn x:Name="StoryCol" attachedProperties:DataGridColumnsGroupProperty.ColGroup="FirstGroup" Header="{x:Static p:Resources.Story}" IsReadOnly="True" Binding="{Binding Story}" Visibility="Visible" />
<DataGridTextColumn x:Name="CadIdCol" attachedProperties:DataGridColumnsGroupProperty.ColGroup="SecondGroup" Header="{x:Static p:Resources.CadId}" IsReadOnly="False" Binding="{Binding CadId}" Visibility="Visible" />
Using a DataTrigger should work as far as the binding to the attached property is concerned:
<DataTrigger Binding="{Binding Path=(attachedProperties:DataGridColumnsGroupProperty.ColGroup)}" Value="FirstGroup">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>

INotifyPropertyChange ignored in binding to a DataTrigger

I'm working on some code that has a Button that contains an image and some text, and which should display either the image, the text, or both, depending upon the value of a bound property. The code is currently using Styles and DataTriggers:
public enum ButtonStyle { Image, Text, Both };
public class ViewModel : INotifyPropertyChanged
{
private ButtonStyle _buttonStyle;
public ButtonStyle buttonStyle
{
get { return this._buttonStyle; }
set
{
this._buttonStyle = value;
notifyPropertyChanged("buttonStyle");
}
}
And:
<UserControl.Resources>
<Style x:Key="buttonTextStyle" TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=buttonStyle}"
Value="{x:Static local:ButtonStyle.Text}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="buttonImageStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=buttonStyle}"
Value="{x:Static local:ButtonStyle.Image}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Button>
<StackPanel>
<Image Source="..." Style="{StaticResource buttonImageStyle} />
<Label Style={StaticResource buttonTextStyle}>My Text</Label>
</StackPanel>
</Button>
My problem? The button doesn't change when I change the value of the buttonStyle property in the view model. This control is in a tab, and if I switch to another tab and then switch back, the button updates to reflect the current value of the buttonStyle property, but it does not change until I do.
It looks like the DataTrigger is processed only when the control is rendered, and does not re-render when the bound value is modified, despite the bound value raising a PropertyChanged event.
Any ideas?
Try NotifyOnSourceUpdated=True on each of your data triggers.
<DataTrigger Binding="{Binding Path=buttonStyle, NotifyOnSourceUpdated=True}"
Value="{x:Static local:ButtonStyle.Text}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
I think this is a nicer way to refer to enums in your DataTrigger:
<Style x:Key="buttonImageStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=buttonStyle}">
<DataTrigger.Value>
<local:ButtonStyle>Text</local:ButtonStyle>
</DataTrigger.Value>
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
The value of the resource changes during runtime, thats why you should use DynamicResource instead of StaticResource:
Style="{DynamicResource buttonImageStyle}"
Here's an idea - any time you have a binding problem and it looks like INotifyPropertyChanged isn't working, check and double check and make damned sure that you spelled the name of the property right, in your PropertyChangedEventArgs().
Sorry for the trouble.

Resources