views:

952

answers:

4

Hello, I want to change the foreground color of cells that hold negative numbers, but I don't know how to specify the DataTrigger that would let me. I'm using something like this:

<Style x:Key="NumberCellStyle" BasedOn="{StaticResource CellStyle}">
 <Style.Triggers>
  <DataTrigger Binding="{Binding Converter={StaticResourceExtension SignConverter}}" Value="-1">
   <Setter Property="TextBlock.Foreground" Value="Red"/> 
  </DataTrigger>
 </Style.Triggers>
</Style>

But in the SignConverter converter I get the whole ViewModel instead of the numeric value I want to convert. I want this to work across the app, without me needing to specify the correct Path for each binding.

Thank you very much!

A: 

What control are you applying the style too? It sounds like whatever you are applying it to doesn't have any specific bindings set for itself, so it is just inheriting its parents' value, which ends up being your ViewModel instance.

Update: Based on the comment, I think that you need to specify a Path in the Binding expression of the style. Since no path is specified, it just uses the current DataContext, which ends up being the entire ViewModel instance.

Andy
I'm using WPFToolkit's DataGrid, where you specify the bindings for different types of columns. In this case it is the ElementStyle of a DataGridTextColumn. The cells display numbers, but I get the ViewModel instead.
Pablo Montilla
I understand that, what I want is not to specify a Path, so that any column that will hold a number and gets this style, can be painted Red if the number is negative. Is there any way I can get the Path specified in another Binding?
Pablo Montilla
Honestly, I'm not sure. If the column had a DataContext, I'd say to bind the data for the column to that and that would work, however it looks like it doesn't have a DataContext. So I'm not sure if there is a way, unfortunately.
Andy
OK, no problem. Thanks for your time! =)
Pablo Montilla
A: 

OK, I didn't find a way to solve my original problem, but I'll work around it by using a DataGridTemplateColumn with templates that correctly set the Foreground color depending on the value that's bind to them.

Pablo Montilla
A: 

Better way, write a custom column.

The code follows for anyone that's in the same situation:

public class DataGridDecimalColumn : DataGridTextColumn
{
 Binding               foregroundBinding;
 DecimalBrushConverter brushConverter = new DecimalBrushConverter {
  NegativeBrush = Brushes.Red, 
  PositiveBrush = Brushes.Black, 
  ZeroBrush     = Brushes.Black,
 };

 protected override FrameworkElement 
 GenerateElement(DataGridCell cell, object dataItem)
 {
  var element = base.GenerateElement(cell, dataItem) as TextBlock;
  element.SetBinding(TextBlock.ForegroundProperty, GetForegroundBinding());
  return element;
 }

 Binding
 GetForegroundBinding()
 {
  if(foregroundBinding == null) {
   var binding       = (Binding)Binding;
   foregroundBinding = new Binding {
    Path      = binding.Path,
    Converter = BrushConverter,
   };
  }
  return foregroundBinding;
 }

 public DecimalBrushConverter 
 BrushConverter
 {
  get { return brushConverter; }
  set { brushConverter = value; }
 }
}

DecimalBrushConverter simple takes a decimal? and converts it to one of the specified brushes depending on its value.

Pablo Montilla
A: 

How would you get this code to read the IsSelected property of the DataGrid itself? I've tried the following code but can't work out how to get the bool value into the ConverterParameter, where the DecimalBrushConverter reads the parameter and provides the SelectedBrush if isSelected==true.

public class DataGridDecimalColumn : DataGridTextColumn { private readonly DecimalBrushConverter _brushConverter = new DecimalBrushConverter { NegativeBrush = Brushes.Red, PositiveBrush = Brushes.Black, ZeroBrush = Brushes.Black, SelectedBrush = Brushes.White };

    private Binding _foregroundBinding;

    private DecimalBrushConverter BrushConverter
    {
        get { return _brushConverter; }
    }



    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var element = base.GenerateElement(cell, dataItem) as TextBlock;

        if (element != null)
            element.SetBinding(TextBlock.ForegroundProperty, GetForegroundBinding());

        return element;
    }



    private Binding GetForegroundBinding()
    {
        if (_foregroundBinding == null)
        {
            var binding = (Binding) Binding;
            var bindingToRow = new Binding
                                   {
                                       Path = new PropertyPath("IsSelected"),
                                       RelativeSource=new RelativeSource(RelativeSourceMode.FindAncestor,typeof(DataGridRow),1)
                                   };
            _foregroundBinding = new Binding
                                     {
                                         Path = binding.Path,
                                         Converter = BrushConverter,
                                         ConverterParameter = bindingToRow
                                     };
        }
        return _foregroundBinding;
    }
}