Click here to Skip to main content
15,879,474 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello,

I need to make a multicolor in a single cell based on cell value in WPF datagrid.

For example:
I have a column which header is "InitialNames" and another column with a header "Available"

Let's say that it contains for example the following:
InitialNames
ABC/BD
BVF/GFD/YA
BD

Avaiable
0/1
0/0/0
1

It is all the time the substring.count for both columns in one row are the same.

What I need is that to substring the cell "available" based on "/" and if the value is 1 then the color of the same index in InitialNames column will be red.

I know how to do it in code using TextBlock.Inlines but I don't know how to replace the result in the datagrid cell "InitialNames" with the new inlines colored string.
Posted

The simplest is to use a converter, I have a color converter that I use to change the colors of 2 cells based on values in the object bound to the row.

You add the converter to the resources and then

XML
<Page.Resources>
        <con:StatusToColorConverter x:Key="StatusToColorConverter"/>
        <style x:key="RowColorConverted" targettype="{x:Type TextBlock}" xmlns:x="#unknown">
            <setter property="Background" value="{Binding StatusCode, Converter={StaticResource StatusToColorConverter}}" />
        </style>


and then find the element you want and use the style

XML
<DataGridTextColumn Header="Job Title Name"  Width="2*" Binding="{Binding HdrJobTitleName}" ElementStyle="{StaticResource RowColorConverted}"/>
<DataGridTextColumn Header="Status" Width="1.75*" Binding="{Binding StatusDesc}" x:Name="StatusCol" ElementStyle="{StaticResource RowColorConverted}">


This is my value converter code.

C#
public class StatusToColorConverter : IValueConverter
 {
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
         SolidColorBrush rtn = null;
         string input = value as string;
         switch (input)
         {
             case MMGlobal.NewStatusCode:
                 rtn = new SolidColorBrush(Colors.LawnGreen);
                 break;
             case MMGlobal.ErrorStatusCode:
                 rtn = new SolidColorBrush(Colors.Red);
                 break;
             case MMGlobal.AwaitingStatusCode:
                 rtn = new SolidColorBrush(Colors.Yellow);
                 break;
             case MMGlobal.CompleteStatusCode:
                 rtn = new SolidColorBrush(Colors.Gray);
                 break;
             case MMGlobal.ProcessStatusCode:
                 rtn = new SolidColorBrush(Colors.Lavender);
                 break;
             default:
                 rtn = new SolidColorBrush(Colors.GhostWhite);
                 break;
         }

         return rtn;
     }

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
         throw new NotImplementedException();
     }
 }
 
Share this answer
 
The only (that I can think of) way to have a variable number of pieces of a text column in different colors (based on two independent values) is to extend the TextBlock control to self-construct its content. Here's what I've done.
C#
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

namespace WpfApplication3
{
  public class NameAvailableTextBlock : TextBlock
  {
    public string InitialName
    {
      get { return (string)GetValue(InitialNameProperty); }
      set { SetValue(InitialNameProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty InitialNameProperty =
        DependencyProperty.Register("InitialName", typeof(string), typeof(NameAvailableTextBlock), new PropertyMetadata(string.Empty, NameAvailableChanged));

    public string Available
    {
      get { return (string)GetValue(AvailableProperty); }
      set { SetValue(AvailableProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Available.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AvailableProperty =
      DependencyProperty.Register("Available", typeof(string), typeof(NameAvailableTextBlock), new PropertyMetadata(string.Empty, NameAvailableChanged));

    private static void NameAvailableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      ((NameAvailableTextBlock)d).DoNameAvailableChanged();
    }

    private void DoNameAvailableChanged()
    {
      Inlines.Clear();
      // check for either InitialName or Available == null
      string[] names = InitialName.Split('/');
      string[] avail = Available.Split('/');
      if (names.Length != available.Length)
        return;   // just bail-out until the data is what we want to see
      for (int i = 0; i < names.Length; ++i)
      {
        if (i > 0)
        {
          Inlines.Add(new Run("/"));
        }
        var run = new Run(names[i]);
        Inlines.Add(run);
        if (avail[i].Trim() == "1")
        {
          run.Foreground = Brushes.Red;
        }
      }
    }
  }
}

and
XML
<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication3"
        Title="MainWindow"
        Height="350"
        Width="525">
  <Grid>
    <local:NameAvailableTextBlock Width="400"
                                  Height="200" 
                                  InitialName="{Binding InitialNames}"
                                  Available="{Binding Available}" />
  </Grid>
</Window>


With a DummyDataContext set in MainWindow.xaml.cs:
C#
using System.Windows;

namespace WpfApplication3
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
  {
    public class DummyDataContext
    {
      public string InitialNames { get { return "YVD/LKL/DDS"; } }
      public string Available { get { return "1/0/1"; } }
    }

    public MainWindow()
    {
      InitializeComponent();
      DataContext = new DummyDataContext();
    }
  }

}

For use in a DataGrid, just put the local:NameAvailableTextBlock in the template for the column of the grid.
(A full FlowDocument probably would be overkill!)
 
Share this answer
 
v3
Thank you for your reply

your suggestion will change the color for the cell but I want to use multicolor in single cell.

the following table will make it easier to understand:

If available column as below:

Available
0/1
0/0/0
1
1/0/1
0/0

The InitialName column will be as below:

InitialNames
ABC/BD
BVF/GFD/YA
BM
YVD/LKL/DDS
HGT/FDS

note: instead of bold, it will be red color but I don't know how to make it red in my reply.
 
Share this answer
 
Comments
Matt T Heffron 21-Jan-14 17:27pm    
The correct way to add information to clarify the question is to use the "Improve question" in green at the bottom of your original posting. Solutions are for actual proposed/suggested solutions.
fahood12 22-Jan-14 13:48pm    
Oh sorry, I will in future

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900