简体   繁体   中英

Binding DataGridTextColumn color from C# codebehind

Similar to WPF - help converting XAML binding expression to codebehind

I am attempting to use Binding to change the color of certain elements in a DataGridTextColumn. Because I need an arbitrary number of DataGrids in separate tabs, I am creating them iteratively in the codebehind. Here is my code for creating the column:

// create a value column
column = new DataGridTextColumn();
column.Binding = new Binding("Value");
BindingOperations.SetBinding(column, DataGridTextColumn.ForegroundProperty, new Binding("TextColor"));
listGrid.Columns.Add(column);

The Value binding works fine, but the TextColor property's getter never gets called.

The grid's ItemsSource property is set to a list of VariableWatcher objects, and here are some of its properties:

public bool Value
{
    get { return _variable.Value; }
}
// used to set DataGridTextColumn.Foreground
public Brush TextColor
{
    get
    {
        Color brushColor;
         if (_valueChanged)
            brushColor = Color.FromRgb(255, 0, 0);
        else
            brushColor = Color.FromRgb(0, 0, 0);
         return new SolidColorBrush(brushColor);
    }
}

VariableWatcher implements INotifyPropertyChanged as follows:

public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string info)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

In one of VariableWatcher's methods, I have the following lines:

_valueChanged = true;
NotifyPropertyChanged("Value");
NotifyPropertyChanged("TextColor");

Stepping over the "Value" line activates a breakpoint in the Value getter, and the Value text is updated in the display. However, stepping over the "TextColor" line does NOT activate the breakpoint in the TextColor getter, and the text color does not change. Any idea what's going on here?

EDIT: Here is the answer, thanks to Damascus. (I would have put this in a comment on his answer, but it wouldn't format my code properly.) I added this to the XAML file:

<Window.Resources>
    <Style x:Key="BoundColorStyle" TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="{Binding TextColor}" />
    </Style>
</Window.Resources>

and in the C# code, I replaced the BindingOperations line with

column.ElementStyle = this.FindResource("BoundColorStyle") as Style;

Workaround for this:

Create a style in your resources, looking like that:

<Style x:Key="MyStyle" TargetType="{x:Type TextBlock}">
  <Setter Property="Foreground" Value="{Binding TextColor}" />
</Style>

And set this style in the ElementStyle property of your DataGridColumn , should be something like that in your code:

column = new DataGridTextColumn();
column.Style = this.FindResource("MyStyle") as Style;

The reason for it being that ElementStyle directly works in the column's Content (ie. the TextBlock displaying a value)

It can be achieved through code behind as well without style. The important point is to set binding source explicitly (look in below code) for new binding expression that is set for target property .

In this example, DataGrid generates dynamic columns and is bounded with an object of ColloectionViewSource (ie cycleDataview) and the source of cycleDataview is an object of ObservableCollection that is cycleRecord.

// Create view source

this.cycleDataview = new CollectionViewSource();
this.cycleDataview.Source = this.cycleRecords;

 // Set Item Source to data grid
 this.DataGridCycleData.ItemsSource = this.cycleDataview.View;

// Generate Columns for datagrid
 var columns = this.cycleRecords.First().CyclePartCols.Select((x, i) => new {PreDescriptor =  x.PreDescriptor, Index = i }).ToArray();

foreach (var column in columns)
{

  Binding binding = new Binding(string.Format("CyclePartCols[{0}].PartValue", column.Index));

  Binding bindingColor = new Binding(string.Format("CyclePartCols[{0}].TextColor", column.Index));
  **bindingColor.Source = this.cycleRecords;** // Binding source is required to set

  DataGridTextColumn dgc = new DataGridTextColumn();


  txtblckCol.Text = column.PreDescriptor;
  dgc.Header = txtblckCol;
  dgc.Binding = binding;
  this.DataGridCycleData.Columns.Add(dgc);
  BindingOperations.SetBinding(dgc, DataGridTextColumn.ForegroundProperty, bindingColor);                

}

Use the workaround from damascus but only with code behind:

var myStyle = new Style
{
   TargetType = typeof(TextBlock)
};
textColumnStyleExt.Setters.Add(new Setter(TextBlock.ForegroundProperty, new Binding("TextColor"));
column = new DataGridTextColumn();
column.Binding = new Binding("Value");
column.ElementStyle = myStyle;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM