In the XAML below, the command property is correctly working only with Column B. Clicking on Column A's header is not invoking command's execute method. The difference is that in Column B, DataGridColumnHeader is instantiated explicitly.
On other hand, the second part of style, the trigger that sets background base on Pressed state is working for both columns.
Why does the Command property work with Column B & not with Column A ?
<DataGrid x:Name="Test"
ItemsSource="{Binding Items}"
AutoGenerateColumns="False" >
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Command"
Value="{Binding MyCommand}"/>
<Setter Property="CommandParameter"
Value="{Binding Path=Content, RelativeSource={RelativeSource Self}}"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTextColumn FontSize="12"
Header="Column A"
Width="200"
Binding="{Binding AData}" />
<DataGridTextColumn FontSize="12"
Width="200"
Binding="{Binding BData}">
<DataGridTextColumn.Header>
<DataGridColumnHeader Content="Column B" />
</DataGridTextColumn.Header
>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
EDIT
Data context:
namespace TestColumnHeaderCommandBinding
{
public class Item
{
public int AData { get; set; }
public string BData { get; set; }
}
public class MyCommand : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
MessageBox.Show(parameter.ToString() + " clicked");
}
#endregion
}
public class DataContext
{
public DataContext()
{
MyCommand = new TestColumnHeaderCommandBinding.MyCommand();
Items = new List<Item>(5);
Items.Add(new Item { AData = 1, BData = "One" });
Items.Add(new Item { AData = 2, BData = "Two" });
Items.Add(new Item { AData = 3, BData = "Three" });
Items.Add(new Item { AData = 4, BData = "Four" });
Items.Add(new Item { AData = 5, BData = "Five" });
}
public MyCommand MyCommand { get; set; }
public List<Item> Items { get; set; }
}
}
If you don't explicitly specify the content of the header, it will just contain a simple string, which will not inherit the DataContext of the containing DataGrid.
You should see a warning in the Visual Studio output window containing something like this:
'MyCommand' property not found on 'object' ''String'
To fix that, you can make the binding target the DataContext of the DataGrid:
<Setter Property="Command"
Value="{Binding DataContext.MyCommand,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
Related
I would like to change the picture in the cell when the user clicks on the picture. The initial picture is the "right arrow" and when the user clicks the "right arrow" it should be "red x" but the icon does not change. The value of property (Binding value[3]) changes every time to 0 and 1 so it works fine.
Here is my code:
<GridViewColumn Header="Functions">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image x:Name="MoveImg" Cursor="Hand" ToolTip="Move Losses" MaxWidth="20" MaxHeight="20" Margin="3,3,3,3" MouseLeftButtonUp="MoveImg_MouseLeftButtonUp" >
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Value[3]}" Value="1">
<Setter Property="Source" Value="pack://application:,,,/Resources/x.ico"/>
</DataTrigger>
<DataTrigger Binding="{Binding Value[3]}" Value="0">
<Setter Property="Source" Value="pack://application:,,,/Resources/right_arrow.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
And the code in DtListView.xaml.cs
Dictionary<string, double[]> prDict = new Dictionary<string, double[]>();
Dictionary<string, string[]> lossTransferDict = new Dictionary<string, string[]>();
public Dictionary<string, double[]> PrDict { get => prDict; set => prDict = value; }
public DtListView()
{
InitializeComponent();
}
private void MoveImg_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (TopLossesLv.SelectedItems != null)
{
foreach (KeyValuePair<string, double[]> item in TopLossesLv.SelectedItems)
{
if (!lossTransferDict.ContainsKey(item.Key))
{
lossTransferDict.Add(item.Key, new string[4] { line, item.Value[0].ToString(), item.Value[1].ToString(), item.Value[2].ToString()});
prDict[item.Key][3] = 1; // Modify Value for Picture change
}
else
{
lossTransferDict.Remove(item.Key);
prDict[item.Key][3] = 0; // Modify Value for Picture change
}
}
}
}
This is not C. This is C#. C# is object oriented. Binding to an array of related values is not a good idea for many reasons. Instead bind to an object, that encapsulates the related values of the array.
Instead of binding to a dictionary of arrays, you should bind to a collection of objects. To do this, you would need to convert the array into a class, which implements INotifyPropertyChanged.
Each field of the array becomes a class property. You should apply this refactoring to all your Binding.Source, where the source is an arrays of values. At the end you should be able to bind to lists only.
Avoid binding controls to dictionaries or arrays.
This is a simple example how to use objects (data models) to populate a ListView and change the GridView cell content (the Image) based on the value of a property SimpleDataObject.IsActive of the data model SimpleDataObject:
SimpleDataObject.cs
class SimpleDataObject : INotifyPropertyChaged
{
// Constructor
public SimpleDataObject(string data) => this.DataValue = data;
private bool isActive;
public bool IsActive
{
get => this.isActive;
set
{
this.isActive = value;
OnPropertyChanged();
}
}
private string dataValue;
public string DataValue
{
get => this.dataValue;
set
{
this.dataValue = value;
OnPropertyChanged();
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
ViewModel.cs
// Binding source
class ViewModel : INotifyPropertyChaged
{
public ViewModel()
{
this.SimpleDataObjects = new ObservableCollection<SimpleDataObject>()
{
new SimpleDataObject("Data value 1"),
new SimpleDataObject("Data value 2"),
new SimpleDataObject("Data value 3")
}
}
public ObservableCollection<SimpleDataObject> SimpleDataObjects { get; set; }
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
private void OnImageMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var image = sender as Image;
var dataItem = image.DataContext as SimpleDataObject;
dataItem.IsActive = true; // Toggle image
}
}
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<ListView ItemsSource="{Binding SimpleDataObjects}">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Functions">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="{x:Type SimpleDataObject}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DataValue}"/>
<Image MouseLeftButtonUp="OnImageMouseLeftButtonUp">
<Image.Style>
<Style TargetType="Image">
<!-- Default value. Applies when the observed property IsActive returns false -->
<Setter Property="Source" Value="pack://application:,,,/Resources/right_arrow.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Source" Value="pack://application:,,,/Resources/x.ico" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
</Window>
I am working on WPF using MVVM pattern.
I have a requirement to create a datagrid with dynamic columns. First column is of type datagridtextcolumn and should contain manager names (this column is static), but from the second column it is of type datagridcheckboxcolumn and many employees can map to single manager.
I have three classes
MainViewmodel
ManagerViewmodel
EmployeeViewmodel
My class goes like this
class mainViewmodel()
{
// to hold the managers
public observablecollection<ManagerViewmodel> Managers{get; set;}
}
class ManagerViewmodel()
{
//To hold the manager Names
Public string ManagerName{get; set;}
//To hold the list of employees
public observablecollection<employeeViewmodel> Employees{get;set;}
}
class employeeViewmodel()
{
// to hold a boolean value whether employee to reporting to manager
public bool IsReprting {get;set;}
}
in my main.XAML
<DataGrid x:Name="MyDataGrid" CanUserAddRows="False" CanUserDeleteRows="False" CanUserSortColumns="False" AutoGenerateColumns="False" IsEnabled="True" SelectionMode="Extended" SelectionUnit="Cell">
<DataGrid.Resources>
<Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="#FFDEEAF6"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="0 0 1 1"/>
<Setter Property="Height" Value="auto"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn header = "Manager">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ManagerName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
in my main.CS
public main()
{
Initializecomponent();
MainViewmodel Main = MainViewmodel();
this.datacontext = Main;
//adding datagridcheckboxcolumns dynamically
for (int i = 0; i < Managers.employees.count; i++)
{
DataGridCheckBoxColumn checkBoxColumn = new DataGridCheckBoxColumn();
checkBoxColumn.Header = Main.Managers[i].ManagerName;
checkBoxColumn.IsReadOnly = false;
DG.Columns.Add(checkBoxColumn);
}
ListCollectionView listCollection = new ListCollectionView(Main.Managers);
this.MyDataGrid.ItemsSource = listCollection;
}
Here the manager name is binded in my xaml code now
i want to bind IsReporting propert of each employee to the each row of datagridcheckboxcolumn.
I have a listview in my WPF application and the first column is a Checkbox. This checkbox is bound to the IsSelected property of my model and the event propogation happens correctly.
I also have a Checkbox in the same column's header and want to implement a 'Select All' feature where it checks all the listview items.
I'm using pattern MVVM.
The Event doesn't fire!
Can someone explain what I am doing wrong here..
The relevant code portions are mentioned below..
XAML:
<ListView Grid.Row="0"
ItemsSource="{Binding Path=WorkOrders}"
Margin="5,10,5,5"
Name="WorkOrders"
SelectionMode="Multiple"
FontSize="13"
Background="AliceBlue"
BorderBrush="AliceBlue">
<!--Style of items-->
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<!--Properties-->
<Setter Property="Control.HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Control.VerticalContentAlignment" Value="Center" />
<!--Trigger-->
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView >
<GridViewColumn CellTemplate="{StaticResource CheckBoxDataTemplate}" Width="80" >
<GridViewColumn.HeaderTemplate>
<DataTemplate>
<CheckBox Command="{Binding Path=SelectAllCommand}" />
</DataTemplate>
</GridViewColumn.HeaderTemplate>
</GridViewColumn>
<GridViewColumn Header="WorkOrder" CellTemplate="{StaticResource DetailIdenTemplate}" Width="300"/>
</GridView>
</ListView.View>
</ListView>
Model:
public class WorkOrder
{
public int CD_WORK_ORDER { get; set; }
public string ID_WORK_ORDER { get; set; }
public bool IsSelected { get; set; }
}
ViewModel:
public class LockWorkOrderSelectionViewModel : ViewModelBase
{
RelayCommand _selectAllCommand;
public ICommand SelectAllCommand
{
get
{
if (_selectAllCommand == null)
{
_selectAllCommand = new RelayCommand(
param => SelectAllElement(),
param => CanSelectAll);
}
//RaiseEvent(new RoutedEventArgs(SearchEvent));
return _selectAllCommand;
}
}
private bool _selectedAllElement;
public bool SelectAllElement()
{
foreach (var item in WorkOrders)
{
item.IsSelected = true;
}
return true;
}
public bool CanSelectAll
{
get { return true; }
}
public List<string> WorkOrdersList
{
get { return _workOrdersList; }
}
private ObservableCollection<WorkOrder> _workOrders = new ObservableCollection<WorkOrder>();
public ObservableCollection<WorkOrder> WorkOrders
{
get
{
int progr = 1;
foreach (var item in WorkOrdersList)
{
if (_workOrders.FirstOrDefault(i => i.ID_WORK_ORDER == item) == null)
{
_workOrders.Add(new WorkOrder { CD_WORK_ORDER = progr, ID_WORK_ORDER = item, IsSelected = false });
progr++;
}
}
return _workOrders;
}
}
}
<CheckBox IsChecked="{Binding DataContext.SelectAll, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
Works for me.
I have a TreeView that I want to add two different node types to, with each type having its own HierachicalDataTemplate. I have this working (Code Below)
What I would like is when any node in the tree is selected, I want the template to change for that node, with a different template for BoolNode nodes and a different template for the CompareNodes. I have found some examples using Styles and Triggers but they are all for a TreeView, where all nodes share the same template.
TreeView Xaml:
<TreeView Name="m_kTest">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type self:BoolNode}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding OpText}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type self:CompareNode}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Header}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding OpText}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
IQueryNode:
public interface IQueryNode
{
ObservableCollection<IQueryNode> Children { get; }
int OpIndex { get; set; }
String OpText{get;}
}
BoolNode:
public class BoolNode :IQueryNode
{
public int OpIndex { get; set; }
public String OpText { get { ... } }
public ObservableCollection<IQueryNode> Children { get; private set; }
public BoolNode()
{
Children = new ObservableCollection<IQueryNode>();
}
}
CompareNode:
public class CompareNode: IQueryNode
{
public ObservableCollection<IQueryNode> Children { get; private set; }
public int OpIndex { get; set; }
public String OpText {get {...} }
public String Header { get; set; }
public String Value { get; set; }
public CompareNode()
{
Children = new ObservableCollection<IQueryNode>();
}
}
I got this to work in a sort of "hacky" way.
I added a "IsSelected" property to my two classes and bound it to the IsSelected property of the TreeViewNode. Then, since I only had two data types I was working with, I added a "IsBoolean" boolean field and triggered the template change on those two values:
TreeView Xaml:
<TreeView Name="m_kTest">
<TreeView.Resources>
<HierarchicalDataTemplate x:Key="BoolDisplayTemplate" DataType="{x:Type self:BoolNode}" ItemsSource="{Binding Children}"> /*template*/ </HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="BoolEditTemplate" DataType="{x:Type self:BoolNode}" ItemsSource="{Binding Children}"> /*template*/ </HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="CompareEditTemplate" DataType="{x:Type self:CompareNode}" ItemsSource="{Binding Children}"> /*template*/ </HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="CompareDisplayTemplate" DataType="{x:Type self:CompareNode}" ItemsSource="{Binding Children}"> /*template*/ </HierarchicalDataTemplate>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsBoolNode}" Value="True"/>
<Condition Binding="{Binding Path=IsSelected}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Value="{StaticResource BoolDisplayTemplate}" Property="HeaderTemplate"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsBoolNode}" Value="True"/>
<Condition Binding="{Binding Path=IsSelected}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Value="{StaticResource BoolEditTemplate}" Property="HeaderTemplate"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsBoolNode}" Value="False"/>
<Condition Binding="{Binding Path=IsSelected}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Value="{StaticResource CompareDisplayTemplate}" Property="HeaderTemplate"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsBoolNode}" Value="False"/>
<Condition Binding="{Binding Path=IsSelected}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Value="{StaticResource CompareEditTemplate}" Property="HeaderTemplate"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
</TreeView>
IQueryNode:
public interface IQueryNode
{
ObservableCollection<IQueryNode> Children { get; }
int OpIndex { get; set; }
String OpText{get;}
bool IsBoolNode { get; }
bool IsSelected { get; set; }
}
BoolNode:
public class BoolNode :IQueryNode
{
public int OpIndex { get; set; }
public String OpText { get { ... } }
public ObservableCollection<IQueryNode> Children { get; private set; }
public bool IsBoolNode{get{return true;}}
public bool IsSelected { get; set;}
public BoolNode()
{
OpIndex = 0;
Children = new ObservableCollection<IQueryNode>();
IsSelected = false;
}
}
CompareNode:
public class CompareNode: IQueryNode
{
public ObservableCollection<IQueryNode> Children { get; private set; }
public int OpIndex { get; set; }
public String OpText{ get{ ... } }
public String Header { get; set; }
public String Value { get; set; }
public bool IsBoolNode { get { return false; } }
public bool IsSelected { get; set; }
public CompareNode()
{
Children = new ObservableCollection<IQueryNode>();
IsSelected = false;
}
}
Here's a way I got to work to get a custom style only on selected items
XML:
<Window x:Name="window"
x:Class="stackoverflowTreeview.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:t="clr-namespace:System;assembly=mscorlib"
xmlns:this="clr-namespace:stackoverflowTreeview"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<this:testConv x:Key="testConv"/>
<Style TargetType="TreeView">
<Setter Property="ItemTemplate">
<Setter.Value>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<ContentControl>
<ContentControl.Style>
<Style>
<Setter Property="ContentControl.Content">
<Setter.Value>
<!-- This is the default, common template -->
<TextBlock Text="{Binding Name, Converter={StaticResource testConv}}"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TreeViewItem}}" Value="True">
<Setter Property="ContentControl.Content">
<Setter.Value>
<ContentControl Content="{Binding}">
<ContentControl.Resources>
<!-- These templates are type specific, change them for your desired types -->
<DataTemplate DataType="{x:Type this:Herp}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type this:Derp}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</HierarchicalDataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TreeView Name="m_kTest" ItemsSource="{Binding Data, ElementName=window}">
</TreeView>
</Grid>
</Window>
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
namespace stackoverflowTreeview
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Data = new List<IHerp>()
{
new Derp("Derp Root", "Derp Root Value")
{
Children = new List<IHerp>()
{
new Herp("Herp Child")
{
Children = new List<IHerp>() {new Derp("Derp Grandchild","Derp GrandChild Value")}
},
new Derp("Derp Child2", "Derp Child2 Value")
{
Children = new List<IHerp>() {new Derp("Derp Grandchild","Derp GrandChild Value")}
},
new Herp("Herp Child")
{
Children = new List<IHerp>() {new Derp("Derp Grandchild","Derp GrandChild Value")}
}
}
}
};
}
public static DependencyProperty dData = DependencyProperty.Register("Data", typeof(List<IHerp>), typeof(MainWindow));
public List<IHerp> Data
{
get { return (List<IHerp>)GetValue(dData); }
set { SetValue(dData, value); }
}
}
public abstract class IHerp : DependencyObject
{
public static DependencyProperty dChildren = DependencyProperty.Register("Children", typeof(List<IHerp>), typeof(IHerp));
public List<IHerp> Children { get { return (List<IHerp>)GetValue(dChildren); } set { SetValue(dChildren, value); } }
public static DependencyProperty dName = DependencyProperty.Register("Name", typeof(string), typeof(IHerp));
public string Name { get{return (string)GetValue(dName);} set{SetValue(dName,value);} }
public IHerp()
{
Children = Children == null ? new List<IHerp>() : Children;
Name = Name == null ? "" : Name;
}
}
public class Herp : IHerp
{
public Herp(string name)
{
Name = name;
}
}
public class Derp : IHerp
{
public string Value { get; set; }
public Derp(string name, string value)
{
Name = name;
Value = value;
}
}
public class testConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return value;
}
catch { return typeof(object); }
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
I've spend a lot of time trying to change row text color on CheckBox click event.
So we need set color to gray if checkbox is checked and return it to normal color if checkbox is not checked.
Please help to get this result (DataGrid bound to xml file).
Upd. Some code:
XAML for row color changing based on column Checked (Checkbox):
<Window.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Foreground" Value="{Binding Checked, Converter={x:Static local:MainWindow.rowCheckedConverter}}" />
</Style>
</Window.Resources>
...
<Grid.DataContext>
<XmlDataProvider x:Name="userTasksProvider" XPath="UserTasks" />
</Grid.DataContext>
...
<DataGrid Name="dgUserTasks" Grid.Column="1" Margin="1,0,0,0"
AutoGenerateColumns="False" HeadersVisibility="None"
ItemsSource="{Binding XPath=Task}">
<DataGrid.Columns>
<DataGridCheckBoxColumn x:Name="cbUserTasksColumn" Width="20"
Binding="{Binding Checked,
Mode=TwoWay}" Header="">
</DataGridCheckBoxColumn>
<DataGridTextColumn
x:Name="Info" Width="*"
Binding="{Binding Info,
Mode=TwoWay}"
Header="" >
</DataGridTextColumn>
...
C# WPF:
public partial class MainWindow : Window
{
public static RowCheckedConverter rowCheckedConverter = new RowCheckedConverter();
...
}
...
public class RowCheckedConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if ((bool)value) {
return new SolidColorBrush(Colors.Gray);
}
else {
return new SolidColorBrush(Colors.Black);
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new Exception("The method or operation is not implemented.");
}
}
Your question is quite vague but I'll try to help.
Consider this example:
<DataGrid ItemsSource="{Binding DataSet}" AutoGenerateColumns="False">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="False">
<Setter Property="Foreground" Value="Gray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}">
</DataGridTextColumn>
<DataGridCheckBoxColumn Binding="{Binding IsActive, Mode=TwoWay}">
</DataGridCheckBoxColumn>
</DataGrid.Columns>
</DataGrid>
and code:
public partial class MainWindow : Window
{
public ObservableCollection<Data> DataSet { get; set; }
public MainWindow()
{
DataSet = new ObservableCollection<Data>();
DataSet.Add(new Data { Name = "First" });
DataSet.Add(new Data { Name = "Second" });
DataSet.Add(new Data { Name = "Third" });
InitializeComponent();
DataContext = this;
}
}
public class Data
{
public string Name { get; set; }
public bool IsActive { get; set; }
}
In this snippet I bound checkbox column to property in Data instance and added style trigger when this property is false. Is this what you where looking for?
Edit after question update
I cannot see in code that your provided where your style is assigned to DataGrid:
<DataGrid RowStyle="{StaticResource myStyle}" ...>
and your style does not declare x:Key property.
If you add this it will work but the static fied/property just smells bad. Consider changing to:
<Style TargetType="DataGridRow" x:Key="myStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding Checked}" Value="False">
<Setter Property="Foreground" Value="Gray"/>
</DataTrigger>
</Style.Triggers>
</Style>
If you are determined to use converter consider changning to:
<Style TargetType="{x:Type DataGridRow}" x:Key="myStyle">
<Setter Property="Foreground" >
<Setter.Value>
<Binding Path="Checked">
<Binding.Converter>
<local:RowCheckedConverter />
</Binding.Converter>
</Binding>
</Setter.Value>
</Setter>
</Style>
This will also eliminate this field.
Use a converter like shown here: http://timheuer.com/blog/archive/2008/07/30/format-data-in-silverlight-databinding-valueconverter.aspx