DXGridControl Is not working CellStyle - wpf

I would like to change the Background, FontWeight, Foreground in dxg:GridColumn.
I wrote this code but unfortunately it does not work.
How can I fix it?
public class CellViewModel {
public string Value { get; set; }
public string FontWeight { get; set; }
public string Foreground { get; set; }
public string Background { get; set; }
}
public class TestItemViewModel {
public CellViewModel Column1 { get; set; }
public CellViewModel Column2 { get; set; }
public CellViewModel Column3 { get; set; }
}
public class TestViewModel {
public TestViewModel() {
this.Items = new ObservableCollection<TestItemViewModel> {
new TestItemViewModel {
Column1 = new CellViewModel { Value = "CCC", FontWeight = "Bold", Foreground = "Red", Background = "Green" },
Column2 = new CellViewModel { Value = "-683,84", FontWeight = "Normal", Foreground = "Red", Background = "SeaGreen" },
Column3 = new CellViewModel { Value = "-683,84", FontWeight = "Normal", Foreground = "Red", Background = "SeaGreen" },
}
};
}
public ObservableCollection<TestItemViewModel> Items { get; set; }
}
<dxg:GridControl HorizontalContentAlignment="Right"
AutoPopulateColumns="False"
ItemsSource="{Binding Path=Performance.Items}">
<dxg:GridControl.Resources>
<DataTemplate x:Key="GridColumnHorizontalContentAlignmentTemplate">
<dxe:TextEdit x:Name="PART_Editor" HorizontalContentAlignment="Right" />
</DataTemplate>
</dxg:GridControl.Resources>
<dxg:GridControl.Columns>
<dxg:GridColumn AllowColumnFiltering="False"
CellTemplate="{StaticResource GridColumnHorizontalContentAlignmentTemplate}"
FieldName="BuyAndHold.Value"
Header="Column 1"
HorizontalHeaderContentAlignment="Right">
<dxg:GridColumn.CellStyle>
<Style TargetType="dxg:CellContentPresenter">
<Setter Property="Background" Value="{Binding Path=Column1.Background}" />
<Setter Property="FontWeight" Value="{Binding Path=Column1.FontWeight}" />
<Setter Property="Foreground" Value="{Binding Path=Column1.Foreground}" />
</Style>
</dxg:GridColumn.CellStyle>
</dxg:GridColumn>
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:TableView AllowEditing="False"
AllowGrouping="False"
AllowSorting="False"
NavigationStyle="None"
PrintTotalSummary="False"
ShowGroupPanel="False"
ShowHorizontalLines="False"
ShowIndicator="False"
ShowTotalSummary="False"
ShowVerticalLines="False" />
</dxg:GridControl.View>
</dxg:GridControl>
I can not understand why there is
<Style TargetType="dxg:CellContentPresenter">
<Setter Property="Background" Value="{Binding Path=BuyAndHold.Background}" />
<Setter Property="FontWeight" Value="{Binding Path=BuyAndHold.FontWeight}" />
<Setter Property="Foreground" Value="{Binding Path=BuyAndHold.Foreground}" />
</Style>
no data binding?
If I set the value manually everything works. For example.
<Setter Property="Background" Value="Red" />
Work Fine.

The binding's Path you are using is wrong.
Use the following syntax:
<Setter Property="Background" Value="{Binding Path=RowData.Row.BuyAndHold.Background}"/>
instead of:
<Setter Property="Background" Value="{Binding Path=BuyAndHold.Background}"/>
Related Example: How to Conditionally Apply Styles (CellStyle)

Related

How to switch Control by DataTrigger in the xaml?

There is a window consist of the two control.
one is TreeView, the other is ListBox.
The code is as shown below.
<Grid Grid.Row="1">
<TreeView x:Name="treeView" BorderThickness="0" Visibility="Visible"
ItemsSource="{Binding TotalCPUs}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<mvvm:EventToCommand Command="{Binding CPUSelectedCommand}"
PassEventArgsToCommand="True"
EventArgsConverter="{localConverters:SelectedItemConverter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
<ListBox x:Name="listBox" BorderThickness="0" Visibility="Collapsed"/>
</Grid>
Now I would like to change the value of the Visibility property of the Control whenever changes property of the ViewModel. (FilterMode True = ListBox Visible, FilterMode False = TreeView = Visible)
To this, I modified my XAML code as below.
<Grid Grid.Row="1">
<TreeView x:Name="treeView" BorderThickness="0" Visibility="Visible"
ItemsSource="{Binding TotalCPUs}">
<TreeView.Style>
<Style TargetType="{x:Type TreeView}">
<Style.Triggers>
<DataTrigger Binding="{Binding FilterMode}" Value="true">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<mvvm:EventToCommand Command="{Binding CPUSelectedCommand}"
PassEventArgsToCommand="True"
EventArgsConverter="{localConverters:SelectedItemConverter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
<ListBox x:Name="listBox" BorderThickness="0" Visibility="Collapsed">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding FilterMode}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</Grid>
Below is the ViewModel code.
public class NewProjectViewModel : DialogViewModel
{
private Generator projectGenerator = new Generator();
public ObservableCollection<ClassHierarchyData> TotalCPUs { get; private set; } = new ObservableCollection<ClassHierarchyData>();
public ObservableCollection<DetailType> FilterCPUs { get; private set; } = new ObservableCollection<DetailType>();
private bool filterMode;
public bool FilterMode
{
get => filterMode;
set
{
if (this.filterMode == value) return;
this.filterMode = value;
this.RaisePropertyChanged("FilterMode");
}
}
private string cpuSearch;
public string CPUSearch
{
get => this.cpuSearch;
set
{
if (this.cpuSearch == value) return;
this.cpuSearch = value;
this.FilterCPUs.Add(new DetailType(typeof(Target), "abc"));
}
}
private Type selectedTerminalItem;
public Type SelectedTerminalItem
{
get => this.selectedTerminalItem;
private set
{
if (this.selectedTerminalItem == value) return;
this.selectedTerminalItem = value;
this.RaisePropertyChanged("SelectedTerminalItem");
}
}
private Type selectedItem;
public Type SelectedItem
{
get => selectedItem;
set
{
if (this.selectedItem == value) return;
this.selectedItem = value;
this.RaisePropertyChanged("SelectedItem");
CreateCommand.RaiseCanExecuteChanged();
}
}
private string solutionName = string.Empty;
public string SolutionName
{
get => this.solutionName;
set
{
if (this.solutionName == value) return;
this.solutionName = value;
this.RaisePropertyChanged("SolutionName");
this.RaisePropertyChanged("SolutionFullPath");
CreateCommand.RaiseCanExecuteChanged();
}
}
private string solutionPath = string.Empty;
public string SolutionPath
{
get => this.solutionPath;
set
{
if (this.solutionPath == value) return;
this.solutionPath = value;
if(this.SolutionPath.Length > 0)
{
if (this.solutionPath.Last() != '\\')
this.solutionPath += "\\";
}
this.RaisePropertyChanged("SolutionPath");
this.RaisePropertyChanged("SolutionFullPath");
CreateCommand.RaiseCanExecuteChanged();
}
}
public bool CreateSolutionFolder { get; set; }
public string SolutionFullPath { get => this.SolutionPath + this.solutionName; }
private RelayCommand searchCommand;
public RelayCommand SearchCommand
{
get
{
if (this.searchCommand == null) this.searchCommand = new RelayCommand(this.OnSearch);
return this.searchCommand;
}
}
private void OnSearch()
{
CommonOpenFileDialog selectFolderDialog = new CommonOpenFileDialog();
selectFolderDialog.InitialDirectory = "C:\\Users";
selectFolderDialog.IsFolderPicker = true;
if (selectFolderDialog.ShowDialog() == CommonFileDialogResult.Ok)
{
this.SolutionPath = selectFolderDialog.FileName + "\\";
}
}
private RelayCommand<Action> _createCommand;
public RelayCommand<Action> CreateCommand
{
get
{
if (this._createCommand == null)
this._createCommand = new RelayCommand<Action>(this.OnCreate, this.CanExecuteCreate);
return this._createCommand;
}
}
private void OnCreate(Action action)
{
projectGenerator.GenerateSolution(this.SolutionPath, this.SolutionName, this.CreateSolutionFolder);
action?.Invoke();
}
private bool CanExecuteCreate(Action action)
{
if (this.SelectedTerminalItem == null) return false;
if (string.IsNullOrEmpty(this.solutionPath)) return false;
if (string.IsNullOrEmpty(this.solutionName)) return false;
return true;
}
private RelayCommand<ClassHierarchyData> cpuSelectedCommand;
public RelayCommand<ClassHierarchyData> CPUSelectedCommand
{
get
{
if (this.cpuSelectedCommand == null)
this.cpuSelectedCommand = new RelayCommand<ClassHierarchyData>(OnCPUSelected);
return this.cpuSelectedCommand;
}
}
private void OnCPUSelected(ClassHierarchyData selected)
{
this.SelectedItem = selected.Data;
this.SelectedTerminalItem = (selected.Items.Count == 0) ? selected.Data : null;
}
private RelayCommand<string> navigateCommand;
public RelayCommand<string> NavigateCommand
{
get
{
if (this.navigateCommand == null)
this.navigateCommand = new RelayCommand<string>((uri) =>
{
Process.Start(new ProcessStartInfo(uri));
});
return navigateCommand;
}
}
public NewProjectViewModel()
{
ClassHierarchyGenerator classHierarchyGenerator = new ClassHierarchyGenerator();
this.TotalCPUs.Add(classHierarchyGenerator.ToHierarchyData(typeof(Target)));
this.FilterCPUs.CollectionChanged += FilterCPUs_CollectionChanged;
}
private void FilterCPUs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
this.FilterMode = (this.FilterCPUs.Count > 0) ? true : false;
}
}
public class DetailType
{
public Type Type { get; }
public string Path { get; }
public DetailType(Type type, string path)
{
Type = type;
Path = path;
}
}
If user input data to the TextBox for filtering then the value of the CPUSearch is changed.
If the value of the CPUSearch is changed then be added test value into the FilterCPUs. (Note CPUSearch property)
when being added value into the FilterCPUs, FilterCPUs_CollectionChanged is called and the value of the FilterMode is changed.
But the above code does not work although be changed the value of the FilterMode. (works well except for functionality related to FilterMode)
Why doesn't the Control switch?
Thanks for reading.
I solved this problem by referring WPF Showing / Hiding a control with triggers
My XAML code updated like this and it works well.
Thanks for your interest.
<Grid Grid.Row="1">
<TreeView x:Name="treeView" BorderThickness="0"
ItemsSource="{Binding TotalCPUs}">
<TreeView.Style>
<Style TargetType="{x:Type TreeView}">
<Style.Triggers>
<DataTrigger Binding="{Binding FilterMode}" Value="true">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding FilterMode}" Value="false">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<mvvm:EventToCommand Command="{Binding CPUSelectedCommand}"
PassEventArgsToCommand="True"
EventArgsConverter="{localConverters:SelectedItemConverter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
<ListBox x:Name="listBox" BorderThickness="0"
ItemsSource="{Binding FilterCPUs}"
SelectedItem="{Binding SelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock FontSize="8" Text="{Binding Path=Path}" Margin="0 0 0 3"/>
<TextBlock Text="{Binding Type.Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{DynamicResource CommonEnableBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource CommonEnableBorderBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource CommonEnableTextBrush}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding FilterMode}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding FilterMode}" Value="false">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</Grid>

Image content disappearing for a Label inside a DataTemplate [duplicate]

I am using Mahapp's DropDownButton
Here is what I have:
using
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
<mah:DropDownButton
Content="my button"
Icon="{DynamicResource appbar_projector_screen}"
ItemsSource="{Binding Path=MySource}">
<mah:DropDownButton.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Path=Title}"/>
<Setter Property="Command" Value="{Binding Path=Command}"/>
<Setter Property="CommandParameter" Value="{Binding Path=Id }"/>
<Setter Property="Icon">
<Setter.Value>
<Image Width="25" Height="25" Source="{Binding IconPath}" />
</Setter.Value>
</Setter>
</Style>
</mah:DropDownButton.ItemContainerStyle>
</mah:DropDownButton>
First I tried using:
<Setter Property="Header">
<Setter.Value>
<StackPanel>
<Image Width="20" Height="20" Source="{Binding IconPath}" />
<TextBlock Text="{Binding Path=Title}" />
</StackPanel>
</Setter.Value>
</Setter>
But that code does not show any image. So then I tried:
<Setter Property="Icon">
<Setter.Value>
<Image Width="25" Height="25" Source="{Binding IconPath}" />
</Setter.Value>
</Setter>
Initializing the Object MySource:
public List<SomeDefinition> MySource{ get; private set; }
MySource= new List<SomeDefinition>
{
new SomeDefinition{Id=1, Title= $#"1", Command = new RelayCommand<object>(SomeMethod1), IconPath = "D:\\ico1.png"},
new SomeDefinition{Id=2, Title= $#"2", Command = new RelayCommand<object>(SomeMethod2), IconPath = "D:\\ico2.png"},
new SomeDefinition{Id=3, Title= $#"3", Command = new RelayCommand<object>(SomeMethod3), IconPath = "D:\\ico3.png"},
new SomeDefinition{Id=4, Title= $#"4", Command = new RelayCommand<object>(SomeMethod4), IconPath = "D:\\ico4.png"},
new SomeDefinition{Id=5, Title= $#"5", Command = new RelayCommand<object>(SomeMethod5), IconPath = "D:\\ico5.png"}
};
having:
public class SomeDefinition
{
public int Id { get; set; }
public string Title{ get; set; }
public ICommand Command { get; set; }
public string IconPath { get; set; }
}
This shows image only for the last value on menu, I canĀ“t figure out what I am missing. Why is it showing only image for last record?
I tested with all images and they are written correctly, they also do exist, so issue is not finding the image file .
Update
So I have tried using #mm8 solution and changed definition Class to:
public class SomeDefinition
{
public int Id { get; set; }
public string Title{ get; set; }
public ICommand Command { get; set; }
public Image IconImage { get; set; }
}
having xaml:
<mah:DropDownButton
Content="my button"
Icon="{DynamicResource appbar_projector_screen}"
ItemsSource="{Binding Path=MySource}">
<mah:DropDownButton.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Path=Title}"/>
<Setter Property="Command" Value="{Binding Path=Command}"/>
<Setter Property="CommandParameter" Value="{Binding Path=Id }"/>
<Setter Property="Icon" Value="{Binding IconImage}" />
</Style>
</mah:DropDownButton.ItemContainerStyle>
</mah:DropDownButton>
and code behind:
var Image = new Bitmap(#"D:\\1.png");
MySource = new List<SomeDefinition>
{
new SomeDefinition{Id=1, Title= $#"1", Command = Command1, IconImage = Image},
new SomeDefinition{Id=2, Title= $#"2", Command = Command2, IconImage = Image},
new SomeDefinition{Id=3, Title= $#"3", Command = Command3, IconImage = Image},
new SomeDefinition{Id=4, Title= $#"4", Command = Command4, IconImage = Image},
new SomeDefinition{Id=5, Title= $#"5", Command = Command5, IconImage = Image}
};
Result is:
How to convert object to Image?
"This shows image only for the last value on menu" - Setter creates only one instance of Image, which can only be displayed in one place.
As a workaround you can declare Image as a non-shared resource, and use it via StaticResource in Setter:
<Image x:Key="StdIcon" x:Shared="False" Width="25" Height="25" Source="{Binding IconPath}" />
<Setter Property="Icon" Value="{StaticResource StdIcon}"/>

Listbox item trigger colour change

I am trying to change the colour of the items in a listbox based on a trigger using MVVM
<Border Grid.Row="1" Width="300" Margin="0,0,20,0" BorderThickness="1,2,1,1" CornerRadius="5" BorderBrush="#FF999393" Background="#FFE9EDF1" >
<ListBox ItemsSource="{Binding LogMessageList, UpdateSourceTrigger=PropertyChanged}" Background="{x:Null}" Margin="3" BorderBrush="{x:Null}" FontSize="13.333" >
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="#FF403E3E" />
<Style.Triggers>
<DataTrigger Binding="{Binding FatalError, UpdateSourceTrigger=PropertyChanged}" Value="Fatal">
<Setter Property="Foreground" Value="Firebrick" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I'm setting the property change correctly but nothing seems to change.
Thanks
EDIT:
Still stuck. Trying
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="#FF403E3E" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},Path=DataContext.FatalError, UpdateSourceTrigger=PropertyChanged}" Value="Fatal">
<Setter Property="Foreground" Value="Firebrick" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
Tried your scenario. Please refer the below code example:
View Model
public class Vm : INotifyPropertyChanged
{
public ObservableCollection<VmUser> VmUsers { get; set; }
private string errorType;
public string ErrorType
{
get { return errorType; }
set
{
errorType = value;
Raise("ErrorType");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void Raise(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class VmUser
{
public string Name { get; set; }
public int Age { get; set; }
}
Set the DataContext of window in constructor :
public MainWindow()
{
Vm = new Vm
{
VmUsers = new ObservableCollection<VmUser>
{
new VmUser { Name = "Gil", Age = 1 },
new VmUser { Name = "Dan", Age = 2 },
new VmUser { Name = "John", Age = 3 },
},
ErrorType = "Fatal"
};
InitializeComponent();
DataContext = TheVm;
}
Defined ListBox in XAML as:
<ListBox Grid.Row="2" ItemsSource="{Binding VmUsers}" DisplayMemberPath="Name" SelectedValuePath="Age">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="#FF403E3E" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},Path=DataContext.ErrorType, UpdateSourceTrigger=PropertyChanged}" Value="Fatal">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
To test the scenario I have wrote a small test to toggle the ErrorType on click on button
private void Button_Click(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as Vm;
if (vm != null)
{
if (vm.ErrorType == "Fatal")
{
vm.ErrorType = "Non Fatal";
}
else
{
vm.ErrorType = "Fatal";
}
}
}
With above example foreground color changes based on ErrorType.

Bound CommandParameter on MenuItem is null

I don't understand why my commandparameter is null when all of the rest of the bindings seem to work, the correct image is displayed, the text is correct and the command CanExecute is called, but for some reason the parameter is null.
<MenuItem Header="Open Recent" ItemsSource="{Binding Path=MRU}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="CommandParameter" Value="{Binding URI}" />
<Setter Property="Header" Value="{Binding URI}" />
<Setter Property="Icon">
<Setter.Value>
<Image Source="{Binding URIImage}" />
</Setter.Value>
</Setter>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
and the view model class:
public class MRU_ViewModel
{
public MRU_ViewModel(string uri)
{
this.URI = uri;
Command = new Commands.Open();
}
public string URI { get; private set; }
public System.Windows.Media.Imaging.BitmapImage URIImage { get { return WorkSpace.GetURIImage(URI); } }
public ICommand Command { get; private set; }
}
and the CanExecute of the command looks like this:
public bool CanExecute(object parameter)
{
return parameter != null && parameter is string; // <---parameter is null
}

WPF DataGridColumnHeader MouseOver - Apply Triggers to the DataGridCell Element

I would like to change background color of that whole datagrid column when I do mouse over of that datagrid column header. Here is code for style I am using.
<Style x:Key="RhinoDataGridBaseStyle" TargetType="{x:Type ctrls:RhinoDataGrid}">
<Style.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="White"></Setter>
<Setter Property="BorderThickness" Value="3"></Setter>
<Setter Property="BorderBrush" Value="#4CB7FF"></Setter>
<Setter Property="Foreground" Value="Black"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Height" Value="26"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
?????????????????????? What Should I write here ??????????????????????????????
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Width" Value="36"></Setter>
</Style>
</Style.Resources>
Please help.
Thanks
Its a little tricky, but you could use an attached property to link the cells to their header.
Here is some code I used a while back (excuse it if its ver long)
Here is the attached property file
public static class GroupMessaging
{
private static readonly Dictionary<string, List<DependencyObject>> messageDictionary = new Dictionary<string, List<DependencyObject>>();
public static readonly DependencyProperty MessageKeyProperty = DependencyProperty.RegisterAttached("MessageKey", typeof(string), typeof(GroupMessaging), new PropertyMetadata(null, OnMessageKeyChanged));
public static void SetMessageKey(UIElement element, string value)
{
element.SetValue(MessageKeyProperty, value);
}
public static string GetMessageKey(UIElement element)
{
return (string)element.GetValue(MessageKeyProperty);
}
public static readonly DependencyProperty MessageProperty = DependencyProperty.RegisterAttached("Message", typeof(string), typeof(GroupMessaging), new PropertyMetadata(null, OnMessageChanged));
public static void SetMessage(UIElement element, string value)
{
element.SetValue(MessageProperty, value);
}
public static string GetMessage(UIElement element)
{
return (string)element.GetValue(MessageProperty);
}
private static void OnMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var key = d.GetValue(MessageKeyProperty);
if (key == null || !messageDictionary.ContainsKey((string)key))
{
return;
}
messageDictionary[(string)key].ForEach(o =>
{
var old = o.GetValue(MessageProperty);
if (o != d && e.NewValue != old)
{
o.SetValue(MessageProperty, e.NewValue);
}
});
}
private static void OnMessageKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue != null && messageDictionary.ContainsKey((string)e.OldValue))
{
messageDictionary[(string)e.OldValue].Remove(d);
}
if (e.NewValue != null)
{
if (!messageDictionary.ContainsKey((string)e.NewValue))
{
messageDictionary.Add((string)e.NewValue, new List<DependencyObject>());
}
messageDictionary[(string)e.NewValue].Add(d);
}
}
}
and here is my XAML
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="core:GroupMessaging.MessageKey" Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid x:Name="headergrid">
<TextBlock Text="{TemplateBinding Content}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="core:GroupMessaging.Message" Value="Active" />
<Setter Property="Background" Value="Aqua" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Prop1">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="templategrid" core:GroupMessaging.MessageKey="Prop1">
<TextBlock Text="{Binding Prop1}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=templategrid, Path=(core:GroupMessaging.Message)}" Value="Active">
<Setter TargetName="templategrid" Property="Background" Value="Aqua" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Prop2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="templategrid" core:GroupMessaging.MessageKey="Prop2">
<TextBlock Text="{Binding Prop2}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=templategrid, Path=(core:GroupMessaging.Message)}" Value="Active">
<Setter TargetName="templategrid" Property="Background" Value="Aqua" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Prop3">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="templategrid" core:GroupMessaging.MessageKey="Prop3">
<TextBlock Text="{Binding Prop3}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=templategrid, Path=(core:GroupMessaging.Message)}" Value="Active">
<Setter TargetName="templategrid" Property="Background" Value="Aqua" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Prop4">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="templategrid" core:GroupMessaging.MessageKey="Prop4">
<TextBlock Text="{Binding Prop4}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=templategrid, Path=(core:GroupMessaging.Message)}" Value="Active">
<Setter TargetName="templategrid" Property="Background" Value="Aqua" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
and here is my viewmodel
public class MainViewModel
{
public List<Item> Items { get; private set; }
public MainViewModel()
{
Items = new List<Item>();
Items.Add(new Item() { Prop1 = "item1_1",
Prop2 = "item1_2", Prop3 = "item1_3", Prop4 = "item1_4"});
Items.Add(new Item() { Prop1 = "item2_1",
Prop2 = "item2_2", Prop3 = "item2_3", Prop4 = "item2_4"});
Items.Add(new Item() { Prop1 = "item3_1",
Prop2 = "item3_2", Prop3 = "item3_3", Prop4 = "item3_4"});
Items.Add(new Item() { Prop1 = "item4_1",
Prop2 = "item4_2", Prop3 = "item4_3", Prop4 = "item4_4"});
Items.Add(new Item() { Prop1 = "item5_1",
Prop2 = "item5_2", Prop3 = "item5_3", Prop4 = "item5_4"});
}
}
public class Item
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
public string Prop4 { get; set; }
}

Resources