Articles in this section
Category / Section

How to customize the style of the combobox in WPF GridDataControl?

2 mins read

Style customization is used to change the look and feel of any control. GridCellComboBoxDropDown is the UIElement loaded in WPF GridDataControl when you set CellType as “ComboBox. Style is applied only in edit mode, when you apply the custom style to GridCellComboBoxDropDown control. Since the UIElement is loaded only in edit mode.

In the following screenshot, GridDataControl is loaded with customized style for GridCellComboBoxDropDown. But, the style is not applied.

Customize combobox style

In Edit mode, Custom style is applied to the GridCellComboBoxDropDown as shown in the following screenshot.

C:\Users\jayapradha\Desktop\Customize combobox style\EditMode.PNG

When you load GridCellComboBoxDropDown, (with its default style), the text is drawn. When you enter edit mode, the GridCellComboBoxDropDown control is loaded directly. Custom style is applied only in an edit mode. You can overcome this problem by overriding GridCellComboBoxCellRenderer, to draw the GridCellComboBoxDropDown control by applying the custom style when GridDataControl is loaded.

Following XAML code example illustrates the customized style for GridCellComboBoxDropDown control where backgrounds are customized.

XAML

<Geometry x:Key="DownArrowGeometry">M 0 0 L 3.5 4 L 7 0 Z</Geometry>
<Style x:Key="ComboBoxReadonlyToggleButton" TargetType="{x:Type ToggleButton}">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Focusable" Value="false" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="Transparent" />     
<Setter Property="ClickMode" Value="Press" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Name="Chrome1"
              Background="Transparent"
              BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="{TemplateBinding BorderThickness}"
                 SnapsToDevicePixels="true">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" SharedSizeGroup="ComboBoxButton" />
</Grid.ColumnDefinitions>
<Border Name="Chrome"
              Grid.Column="1"
              Width="16"
              Background="Green"
              BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="0">
<Path Name="Arrow"
           HorizontalAlignment="Center"
           VerticalAlignment="Center"
           Data="{StaticResource DownArrowGeometry}"
           Fill="Yellow" />
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type syncfusion:GridCellComboBoxDropDown}">
<Setter Property="Background" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type syncfusion:GridCellComboBoxDropDown}">
<Border BorderThickness="0" Padding="0" Background="Transparent">
<Grid Name="MainGrid" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0" MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" />
</Grid.ColumnDefinitions>
<TextBox Name="PART_Textbox"
                Grid.Column="0" 
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                   VerticalContentAlignment="{TemplateBinding VerticalAlignment}"
                   HorizontalContentAlignment="{TemplateBinding HorizontalAlignment}"
                   Background="{TemplateBinding Background}"
                   BorderThickness="0"
                   Foreground="{TemplateBinding Foreground}"
                   IsReadOnly="{Binding Path=IsReadOnly, Mode=TwoWay,
                                          RelativeSource={RelativeSource TemplatedParent}}"
                   Text="{Binding Path=Text, Mode=TwoWay,
                              RelativeSource={RelativeSource TemplatedParent}}" />
<ToggleButton Name="PART_Togg"
                         Grid.Column="1"
                                   Background="Transparent"
                         HorizontalAlignment="Right"
                         IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay,
                                             RelativeSource={RelativeSource TemplatedParent}}"
                         Style="{StaticResource ComboBoxReadonlyToggleButton}" />
<Popup Name="PART_Popup"
              Grid.ColumnSpan="2"
              Margin="1"
              AllowsTransparency="true"
              IsOpen="{Binding Path=IsDropDownOpen, =TwoWay,
                              RelativeSource={RelativeSource TemplatedParent}}"
              Placement="Bottom"
              PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"
              StaysOpen="False">
<theme:SystemDropShadowChrome Name="Shdw"
                                                            MinWidth="{Binding ElementName=MainGrid,
                                                                                 Path=ActualWidth}"
                                                            MaxHeight="{x:Static syncfusion:GridCellDropDownControlBase.MaxDropDownHeight}"
                                                            Color="Transparent">
<Border x:Name="DropDownBorder"
              Background="{TemplateBinding Background}"
              BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="1">
<ContentControl Name="PART_Content" />
</Border>
</theme:SystemDropShadowChrome>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
<Trigger SourceName="PART_Popup" Property="Popup.HasDropShadow" Value="true">
<Setter TargetName="Shdw" Property="Margin" Value="0,0,5,5" />
<Setter TargetName="Shdw" Property="SnapsToDevicePixels" Value="true" />
<Setter TargetName="Shdw" Property="Color" Value="#71000000" />
</Trigger>
<Trigger Property="IsEnabled" Value="true">
<Setter Property="Padding" Value="2" />
<Setter Property="IsTabStop" Value="false" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

 

In the following XAML ComboBox CellType, set to Property1 column that loads GridCellComboBoxDropDown control.

XAML

<syncfusion:GridDataVisibleColumn MappingName="Property1"
                                                                               HeaderText="Car">                 
<syncfusion:GridDataVisibleColumn.ColumnStyle>
<syncfusion:GridDataColumnStyle CellType="ComboBox"
                                                                                 DropDownStyle="Exclusive"
</syncfusion:GridDataVisibleColumn.ColumnStyle>
</syncfusion:GridDataVisibleColumn>

 

The default renderer (GridCellComboBoxCellRenderer) of ComboBox CellType is replaced with CustomRenderer (named as GridCellDropDownRendererExt) that is derived from GridCellComboBoxCellRenderer.

 C#

this.grid.ModelLoaded += grid_ModelLoaded;
void grid_ModelLoaded(object sender, EventArgs e)
{
var oldRenderer = this.grid.Model.Grid.CellRenderers["ComboBox"];
var newRenderer = new GridCellDropDownRendererExt();
newRenderer.RaiseCreated(oldRenderer.CellModel);
newRenderer.GridControl = oldRenderer.GridControl;
this.grid.Model.Grid.CellRenderers.Remove("ComboBox"); //removes the old renderer of ComboBox CellType
this.grid.Model.Grid.CellRenderers.Add("ComboBox", newRenderer); 
}

 

GridCellComboBoxCellRenderer provides virtual methods and properties to customize its behavior. For your use case, you can apply custom style defined in application when GridCellComboBoxDropDown control is drawn. For this you need to override OnRender method in GridCellComboBoxCellRenderer. OnRender method draws GridCellComboBoxDropDown and the Text. While drawing the GridCellComboBoxDropDown, it is converted into VisualBrush and it is drawn at the specified location using DrawingContext. Creating visual brush and drawing text are covered in DrawDropDownPaintExt class that is discussed in the following section.

C#

public class GridCellDropDownRendererExt : GridCellComboBoxCellRenderer
{
private DropDownPaintExt dropDownPaint;
 
public GridCellDropDownRendererExt()
    : base()
{
    dropDownPaint = new DropDownPaintExt();
}
 
protected override void OnRender(DrawingContext dc, RenderCellArgs rca, GridRenderStyleInfo style)
{
    if (rca.CellUIElements != null)
        return;
    Thickness margins = style.TextMargins.ToThickness();
    if (style.HasImageIndex)
    {
        margins = style.AdjustImageWidthAndHeightToMargin(margins, rca.CellRect.Size);
    }            
    Rect textRectangle = rca.SubtractBorderMargins(rca.CellRect, margins);
    textRectangle = rca.SubtractBorderMargins(rca.CellRect, margins);
 
    if (textRectangle.IsEmpty)
    {
        return;
    }
 
    string text = string.Empty;
    if (this.IsCurrentCell(style) && this.HasControlText)
    {
        text = this.ControlText;
    }
    else
    {
        text = this.GetControlText(style);
    }
    if (style.DropdownEdit.ShowButton)
        this.dropDownPaint.DrawDropDown(dc, textRectangle, text, style); 
    else
        GridTextBoxPaint.DrawText(dc, textRectangle, text, style);
}
}
 

 

DropDownPaintExt class draws the GridCellDropDownControl by applying custom style and the Text to the DrawingContext. In the following class GetVisualBrush method converts the UIElement(GridCellComboBoxDropDown) into VisualBrush after merging the customized style to its ResourceDictionary. GridTextBoxPaint.DrawText draws the Text over the VisualBrush.

// Draws the GridCellDropDownControlBase in the cell rectangle. 
public class DropDownPaintExt 
{
private Dictionary<Size, VisualBrush> brushes = new Dictionary<Size, VisualBrush>();
private string VisualStyle = string.Empty;
      
public DropDownPaintExt()
{
 
}
public void DrawDropDown(DrawingContext dc, Rect rc, string text, GridStyleInfo style)
{
    VisualBrush vb = this.GetVisualBrush(rc.Size, style);
    dc.DrawRectangle(vb, null, rc);
    rc = this.ResetTextAreaSize(rc);
    GridTextBoxPaint.DrawText(dc, rc, text, style);
}
private Rect ResetTextAreaSize(Rect rc)
{
    rc.Width = (rc.Width - SystemParameters.VerticalScrollBarWidth) > 0 ? rc.Width - SystemParameters.VerticalScrollBarWidth : 0;
    return rc;
}
                
public VisualBrush GetVisualBrush(Size size, GridStyleInfo style)
{
    if (this.brushes.ContainsKey(size))
    {
      return this.brushes[size];
    }
 
  bool wasAnimated = GridUtil.IsAnimated;
  try
  {
        GridUtil.IsAnimated = false;                
        VisualBrush visualBrush;
        GridCellComboBoxDropDown b = new GridCellComboBoxDropDown();
        b.BeginInit();
        b.Text = null;
        b.Width = size.Width;
        b.Height = size.Height;
        b.EndInit();
        b.Measure(size);
        b.Arrange(new Rect(size));
 
        var str = "/ComboBoxStyling;component/ComboBoxStyle.xaml"; //this path specifies the custom style for combobox celltype. By this way, we can apply the custom style to GridCellComboBoxDropDown
        ResourceDictionary dictionary = new ResourceDictionary();
        dictionary.Source = new Uri(str, UriKind.RelativeOrAbsolute);
        b.Resources.MergedDictionaries.Add(dictionary);  //Returns the visualstyle ResourceDictionary 
 
        visualBrush = new VisualBrush();
        visualBrush.Visual = b;
        this.brushes[size] = visualBrush;
        return visualBrush;
     }
     finally
       {
          GridUtil.IsAnimated = wasAnimated;
       }
}                
}
}

 

Finally, when you override the ComboBox cell renderer, GridCellComboBoxDropDown Control is drawn with customized style as shown in the following screenshot.

 

Final output

Please refer the following sample to apply the custom style for ComboBox CellType.

Sample Link: CustomStyleofComboBox 

Conclusion

I hope you enjoyed learning about how to customize the style for combobox in WPF GridDataControl.

You can refer to our WPF Grid feature tour page to know about its other groundbreaking feature representations. You can also explore our WPF Grid documentation to understand how to create and manipulate data.

For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.

If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forumsDirect-Trac, or feedback portal. We are always happy to assist you!


Did you find this information helpful?
Yes
No
Help us improve this page
Please provide feedback or comments
Comments (0)
Please sign in to leave a comment
Access denied
Access denied