Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

EmptyDataTemplate for WPF or Silverlight DataGrid

4.00/5 (1 vote)
3 Jan 2015CPOL1 min read 9.2K  
Tip to add EmptyDataTemplate in WPF or Silverlight DataGrid

Introduction

ASP.NET has provided EmptyDataTemplate which becomes visible when there are no records to display in DataGrid. User can expect the same thing from WPF application. But there is no inbuilt support for EmptyDataTemplate in WPF. As a programmer, we need to handle this requirement a bit differently. This article provides you with a hint to add EmptyDataTemplate for DataGrid.

Background

WPF provides the ability to apply/change the ControlTemplate for its Templated Controls. DataGrid does have the ControlTemplate which we can use to add EmptyDataTemplate in the DataGrid.

Using the Code

We want our EmptyDataTemplate to be available for DataGrid without making any change in the existing DataGrid control's code and it should be configurable, i.e., user should be able to use it optionally.

Add a class EmptyDataTemplateService, which will contain an attached dependency property of type DataTemplate.

C#
public class EmptyDataTemplateService
{
       public static readonly DependencyProperty EmptyDataTemplateProperty =
           DependencyProperty.RegisterAttached("EmptyDataTemplate", 
           typeof(DataTemplate), typeof(EmptyDataTemplateService), null);
        public static DataTemplate GetEmptyDataTemplate(DataGrid grid)
       {
             return grid.GetValue(EmptyDataTemplateService.EmptyDataTemplateProperty) as DataTemplate;
       }
        public static void SetEmptyDataTemplate(DataGrid grid, DataTemplate emptyDataTemplate)
       {
              grid.SetValue(EmptyDataTemplateService.EmptyDataTemplateProperty, emptyDataTemplate) ;
       }
}

Now we have the EmptyDataTemplate attached property to use inside DataGrid. We can now use this property in DataGrid template. We have added ContentControl above "RowsPresenter" in the following XAML.

XML
<ControlTemplate TargetType="local:DataGrid">
  <Grid>
    <vsm:VisualStateManager.VisualStateGroups>
      <vsm:VisualStateGroup x:Name="CommonStates">
        <vsm:VisualState x:Name="Normal"/>
        <vsm:VisualState x:Name="Disabled">
          <Storyboard>
            <DoubleAnimation Storyboard.TargetName="DisabledVisualElement" 
            Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
          </Storyboard>
        </vsm:VisualState>
      </vsm:VisualStateGroup>
    </vsm:VisualStateManager.VisualStateGroups>
    <Border BorderThickness="{TemplateBinding BorderThickness}" 
    BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="2">
      <Grid Name="Root" Background="{TemplateBinding Background}">
        <Grid.Resources>
          <!--Start: TopLeftHeaderTemplate-->
          <ControlTemplate x:Key="TopLeftHeaderTemplate" 
          TargetType="localprimitives:DataGridColumnHeader">
            <Grid Name="Root">
              <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition Height="Auto" />
              </Grid.RowDefinitions>
              <Border BorderThickness="0,0,1,0" 
              BorderBrush="#FFC9CACA" Background="#FF1F3B53" Grid.RowSpan="2">
                <Rectangle Stretch="Fill" StrokeThickness="1">
                  <Rectangle.Fill>
                    <LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
                      <GradientStop Color="#FCFFFFFF" Offset="0.015" />
                      <GradientStop Color="#F7FFFFFF" Offset="0.375" />
                      <GradientStop Color="#E5FFFFFF" Offset="0.6" />
                      <GradientStop Color="#D1FFFFFF" Offset="1" />
                    </LinearGradientBrush>
                  </Rectangle.Fill>
                </Rectangle>
              </Border>
              <Rectangle VerticalAlignment="Bottom" Width="Auto" 
              StrokeThickness="1" Height="1" Fill="#FFDBDCDC" 
              Grid.RowSpan="2"/>
            </Grid>
          </ControlTemplate>
          <!--End: TopLeftHeaderTemplate-->

          <!--Start: TopRightHeaderTemplate-->
          <ControlTemplate x:Key="TopRightHeaderTemplate" 
          TargetType="localprimitives:DataGridColumnHeader">
            <Grid Name="RootElement">
              <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition Height="Auto" />
              </Grid.RowDefinitions>
              <Border BorderThickness="1,0,0,0" 
              BorderBrush="#FFC9CACA" Background="#FF1F3B53" Grid.RowSpan="2">
                <Rectangle Stretch="Fill">
                  <Rectangle.Fill>
                    <LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
                      <GradientStop Color="#FCFFFFFF" Offset="0.015" />
                      <GradientStop Color="#F7FFFFFF" Offset="0.375" />
                      <GradientStop Color="#E5FFFFFF" Offset="0.6" />
                      <GradientStop Color="#D1FFFFFF" Offset="1" />
                    </LinearGradientBrush>
                  </Rectangle.Fill>
                </Rectangle>
              </Border>
            </Grid>
          </ControlTemplate>
          <!--End: TopRightHeaderTemplate-->
        </Grid.Resources>

        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition/>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition/>
          <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <localprimitives:DataGridColumnHeader Name="TopLeftCornerHeader" 
        Template="{StaticResource TopLeftHeaderTemplate}" Width="22" />
        <localprimitives:DataGridColumnHeadersPresenter 
        Name="ColumnHeadersPresenter" Grid.Column="1"/>
        <localprimitives:DataGridColumnHeader Name="TopRightCornerHeader" 
        Grid.Column="2" Template="{StaticResource TopRightHeaderTemplate}" />
        <Rectangle Name="ColumnHeadersAndRowsSeparator" 
        Grid.ColumnSpan="3" VerticalAlignment="Bottom" 
        Width="Auto" StrokeThickness="1" 
        Height="1" Fill="#FFC9CACA"/>
        <ContentControl Grid.ColumnSpan="2" Grid.Row="1" 
        Visibility="{Binding Path=ItemsSource.Count, 
        Converter={StaticResource CountToVisibilityConverter}}" 
        ContentTemplate="{Binding Path=(local:EmptyDataTemplateService.EmptyDataTemplate), 
        RelativeSource={RelativeSource TemplatedParent}}" 
        HorizontalAlignment="Streach" HorizontalContentAlignment="Streach"/>
        <localprimitives:DataGridRowsPresenter Name="RowsPresenter" 
        Grid.ColumnSpan="2" Grid.Row="2" />
        <Rectangle Name="BottomRightCorner" Fill="#FFE9EEF4" 
        Grid.Column="2" Grid.Row="3" />
        <Rectangle Name="BottomLeftCorner" Fill="#FFE9EEF4" 
        Grid.Row="3" Grid.ColumnSpan="2" />
        <ScrollBar Name="VerticalScrollbar" Orientation="Vertical" 
        Grid.Column="2" Grid.Row="2" Width="18" Margin="0,-1,-1,-1"/>

        <Grid Grid.Column="1" Grid.Row="3">
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <Rectangle Name="FrozenColumnScrollBarSpacer" />
          <ScrollBar Name="HorizontalScrollbar" Grid.Column="1" 
          Orientation="Horizontal" Height="18" Margin="-1,0,-1,-1"/>
        </Grid>

        <dataInput:ValidationSummary Name="ValidationSummary" 
        Grid.Row="4" Grid.ColumnSpan="3" MaxHeight="90"/>
      </Grid>
    </Border>
    <Border x:Name="DisabledVisualElement" IsHitTestVisible="False" 
    Height="Auto" HorizontalAlignment="Stretch" 
    VerticalAlignment="Stretch" Width="Auto" CornerRadius="2" 
    Background="#8CFFFFFF" Opacity="0"/>
  </Grid>
</ControlTemplate>

This sets the EmptyDataTemplate in your project. To use the EmptyDataTemplate, you can use following code inside DataGrid as:

XML
<DataGrid>
    <local:EmptyDataTemplateService.EmptyDataTemplate>
        <DataTemplate>
              <TextBlock Text="Records not found."/>
         </DataTemplate>
       </local:EmptyDataTemplateService.EmptyDataTemplate>
</DataGrid>

Points of Interest

In this way, you can add custom sections to DataGrid such as footer.

License

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