Search code examples
silverlightdatagridglow

Silverlight data grid glow


I'm trying to think of a way to make an individual cell within a datagrid glow.

I know that you can apply a dropshadoweffect like this to the whole grid:

 [data:DataGrid.Effect>
  [DropShadowEffect BlurRadius="100" ShadowDepth="0" Color="Red"/>
 [/data:DataGrid.Effect>

but what I really want to do is have the individual cell glow red when the value is >= to 100. It's a bit of a visual niceness to sort the wheat from the chaff of a large grid.


Solution

  • I had a similar requirement not long ago which I solved as follows:

    DataGrids can be templated of course, so basically I templated the Columns as follows and then had a Converter that painted the background of my widget according to the data bound to this cell.

    <data:DataGridTemplateColumn Header="Overall">
                        <data:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Border Effect="{StaticResource StatusBorderDropShadow}" 
                                    Background="{Binding Overall, Converter={StaticResource MiniStatusLightConverter}, Mode=TwoWay}" 
                                    Style="{StaticResource StatusBorder}" >                                     
                                    <Border.BorderBrush>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="Black" Offset="0"/>
                                            <GradientStop Color="#FF0D9C3B" Offset="1"/>
                                        </LinearGradientBrush>
                                    </Border.BorderBrush>
                                </Border>
                    </DataTemplate>
                        </data:DataGridTemplateColumn.CellTemplate>
    

    Have a look at the background binding how it uses the MiniStatusLightConverter.

    Here is the converter, in your case you will check if the value is >= 100.

    > namespace MyProject.Converters { public class StatusToBrushConverter : IValueConverter { #region Implementation of IValueConverter

    private Dictionary<string, List<Color>> colorsMap;
    
    public StatusToBrushConverter()
    {
      colorsMap = new Dictionary<string, List<Color>>
                    {
                      { "Green", new List<Color> { GetColorFromHexString("#FFC1D7BF"), GetColorFromHexString("#FF21C110"), GetColorFromHexString("#FF074431") } },
                      { "Yellow", new List<Color> { GetColorFromHexString("#FFF2F3EA"), GetColorFromHexString("#FFD7CB10"), GetColorFromHexString("#FFDEFE00") } },
                      { "Red", new List<Color> { GetColorFromHexString("#FFF3EEEA"), GetColorFromHexString("#FFC13C10"), GetColorFromHexString("#FFFE1000") } }
                    };
    }
    
    public static Color GetColorFromHexString(string s)
    {
      s = s.Remove(0, 1);
      var a = System.Convert.ToByte(s.Substring(0, 2), 16);
      var r = System.Convert.ToByte(s.Substring(2, 2), 16);
      var g = System.Convert.ToByte(s.Substring(4, 2), 16);
      var b = System.Convert.ToByte(s.Substring(6, 2), 16);
      return Color.FromArgb(a, r, g, b);
    }
    
    public static string GetColourName(object dtoValue)
    {
      try
      {
        var str = dtoValue.ToString();
        if (str.Contains("#"))
        {
          return str.Split('#')[1];
        }
        return str;
      }
      catch (IndexOutOfRangeException)
      {
        return string.Empty;
      }
    }
    
    public object Convert(object dtoValue, Type targetType, object parameter, CultureInfo culture)
    {
      return new RadialGradientBrush
                          {
                            RadiusX = 0.784, 
                            RadiusY = 0.786, 
                            GradientOrigin = new Point(0.88, 0.115),
                            GradientStops = GetGradientStopCollection(GetColourName(dtoValue)), 
                            RelativeTransform = GetTransformGroupForEffect()
                          };
    }
    
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
      throw new NotImplementedException();
    }
    
    #endregion
    
    public object GetBasicSolidColorBrush(object dtoValue)
    {
      var blueBrush = new SolidColorBrush();
    
      if (dtoValue == null)
      {
        blueBrush.Color = Colors.White;
        return blueBrush;
      }
    
      var value = GetColourName(dtoValue);
    
      if (value == "Green")
      {
        blueBrush.Color = Colors.Green;
      }
      else if (value == "Yellow")
      {
        blueBrush.Color = Colors.Yellow;
      }
      else if (value == "Red")
      {
        blueBrush.Color = Colors.Red;
      }
      else
      {
        blueBrush.Color = Colors.White;
      }
    
      return blueBrush;
    }
    
    private TransformGroup GetTransformGroupForEffect()
    {
      var transform = new TransformGroup();
      transform.Children.Add(new ScaleTransform { CenterX = 0.5, CenterY = 0.5 });
      transform.Children.Add(new SkewTransform { AngleX = 0.0, AngleY = 0.0, CenterX = 0.5, CenterY = 0.5 });
      transform.Children.Add(new RotateTransform { Angle = 4.548, CenterX = 0.5, CenterY = 0.5 });
      return transform;
    }
    
    private GradientStopCollection GetGradientStopCollection(string colorValue)
    {
      var gradientStopCollection = new GradientStopCollection();
    
      var stop1 = new GradientStop { Offset = 0.0 };
      var stop2 = new GradientStop { Offset = 0.200 };
      var stop3 = new GradientStop { Offset = 0.858 };
    
      stop1.Color = colorsMap[colorValue][0];
      stop2.Color = colorsMap[colorValue][1];
      stop3.Color = colorsMap[colorValue][2];
    
      gradientStopCollection.Add(stop1);
      gradientStopCollection.Add(stop2);
      gradientStopCollection.Add(stop3);
    
      return gradientStopCollection;
    }
    

    } }

    I hope at least this brings you ideas. Another approach I tried was create an user control and put it on the CellTemplate rather than just the Border but I had issues and users were screaming at me for this functionality. It works and users are happy, that counts too.

    I hope it helps