xamDataGrid RecordsFound Adorner

At work we are using the Infragistics .NET Advantage For WPF, one control of which is the xamDataGrid. We had a small requirement that was to show a label over the grid whenever no records were obtained for the xamDataGrid.DataSource.

Now I could have tackled this in a simple manner where I placed the xamDataGrid in a Grid along with a Label both with Margin=”0″, and both with HorizontalAlignment=”Stretch” and VerticalAlignment=”Stretch”, and then set the label visibility either in code behind or using a special ValueConverter. But where would be the fun/elegance in that.

So what I decided to do was create a special AdornerDecorator and a special Adorner to do the job.

The AdornerDecorator (DataGridRecordAdornerDecorator) that I wrote allows you to bind a RecordCount DependencyProperty to the source xamDataGrid.Records.Count , and from there the DataGridRecordAdornerDecorator is self managing, and will either show a message (which can be set via the Prompt CLR property).

Its fairly easy to setup here is the most important part of the xaml for the Window that contains the xamDataGrid

   1:          <Grid Background="Gray" Margin="0">
   2:              <igDP:XamDataGrid x:Name="XamDataGrid1"
   3:                                Theme="Onyx"
   4:                                Margin="0"
   5:                                HorizontalAlignment="Stretch"
   6:                                VerticalAlignment="Stretch"
   7:                                DataSource=
   8:                                "{Binding 
   9:                                Source={StaticResource
  10:                                BookData},XPath=Book}">
  11:              </igDP:XamDataGrid>
  12:  
  13:              <local:DataGridRecordAdornerDecorator
  14:                  Prompt="GRRR, Why no stuff"
  15:                  RecordCount="{Binding 
  16:                  ElementName=XamDataGrid1,
  17:                  Path=Records.Count}"/>
  18:  
  19:          </Grid>

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }Where I am simply toggling the DataSource to a small xml data island or to null, in code behind. Here is the code to do this, this is just test code, you SHOULD NOT use this code, it is just to demonstrate the attached demo app.

   1:          private void btnToggle_Click(object sender, RoutedEventArgs e)
   2:          {
   3:              if (zeroTheDataSource)
   4:              {
   5:                  XamDataGrid1.DataSource = null;
   6:              }
   7:              else
   8:              {
   9:                  Binding b = new Binding();
  10:                  b.Source = this.TryFindResource("BookData")
  11:                      as XmlDataProvider;
  12:                  b.XPath = "Book";
  13:                  XamDataGrid1.SetBinding(
  14:                      XamDataGrid.DataSourceProperty, b);
  15:              }
  16:              zeroTheDataSource = !zeroTheDataSource;
  17:              MessageBox.Show(XamDataGrid1.
                   Records.Count.ToString());
  18:  
  19:          }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }So how does the DataGridRecordAdornerDecorator work, well its actually very simple. It simply shows/hides a specialized Adorner (DataGridRecordAdorner) based on the current value of the RecordCount DependencyProperty. Here is the code

   1:  using System;
   2:  using System.Windows;
   3:  using System.Windows.Documents;
   4:  
   5:  namespace WpfApplication1
   6:  {
   7:      public class DataGridRecordAdornerDecorator
               : AdornerDecorator
   8:      {
   9:          #region Data
  10:          private AdornerLayer layer = null;
  11:          private DataGridRecordAdorner adorner = null;
  12:          private FrameworkElement adornedElement;
  13:          private String prompt = "No RECORDS FOUND";
  14:          #endregion
  15:  
  16:          #region Ctor
  17:          public DataGridRecordAdornerDecorator()
  18:          {
  19:              this.Loaded +=
  20:                  new RoutedEventHandler(
  21:                      DataGridRecordAdornerDecorator_Loaded);
  22:          }
  23:          #endregion
  24:  
  25:          #region Public Properties
  26:  
  27:  
  28:          public String Prompt
  29:          {
  30:              get { return prompt;}
  31:              set { prompt = value;}
  32:          }
  33:  
  34:  
  35:          /// <summary>
  36:          /// RecordCount Dependency Property
  37:          /// </summary>
  38:          public static readonly DependencyProperty RecordCountProperty =
  39:              DependencyProperty.Register("RecordCount", typeof(Int32),
  40:                  typeof(DataGridRecordAdornerDecorator),
  41:                      new FrameworkPropertyMetadata((Int32)0,
  42:                      new PropertyChangedCallback(OnRecordCountChanged)));
  43:  
  44:          /// <summary>
  45:          /// Gets or sets the RecordCount property.  
  46:          /// </summary>
  47:          public Int32 RecordCount
  48:          {
  49:              get { return (Int32)GetValue(RecordCountProperty); }
  50:              set { SetValue(RecordCountProperty, value); }
  51:          }
  52:  
  53:          /// <summary>
  54:          /// Handles changes to the RecordCount property.
  55:          /// </summary>
  56:          private static void OnRecordCountChanged(DependencyObject d,
  57:              DependencyPropertyChangedEventArgs e)
  58:          {
  59:              DataGridRecordAdornerDecorator me =
  60:                  (DataGridRecordAdornerDecorator)d;
  61:  
  62:              Int32 value = 0;
  63:              Int32.TryParse(e.NewValue.ToString(), out value);
  64:  
  65:              if (value == 0)
  66:              {
  67:                  me.adorner = new DataGridRecordAdorner(
  68:                      me.adornedElement, me.Prompt);
  69:                  me.layer.Add(me.adorner);
  70:              }
  71:              else
  72:              {
  73:                  if (me.adorner != null &&
  74:                      me.layer != null)
  75:                  {
  76:                      me.layer.Remove(me.adorner);
  77:                      me.adorner = null;
  78:                  }
  79:              }
  80:          }
  81:          #endregion
  82:  
  83:          #region Private Methods
  84:  
  85:          private void DataGridRecordAdornerDecorator_Loaded(
  86:              object sender, RoutedEventArgs e)
  87:          {
  88:              layer = this.AdornerLayer;
  89:              adornedElement = new FrameworkElement {
  90:                  Height = this.Height, Width = this.Width };
  91:              this.Child = adornedElement;
  92:  
  93:  
  94:          }
  95:          #endregion
  96:  
  97:          #region Overrides
  98:          protected override void OnRenderSizeChanged(
  99:              System.Windows.SizeChangedInfo sizeInfo)
 100:          {
 101:              base.OnRenderSizeChanged(sizeInfo);
 102:  
 103:              if (adornedElement != null)
 104:              {
 105:                  adornedElement.Height = sizeInfo.NewSize.Height;
 106:                  adornedElement.Width = sizeInfo.NewSize.Width;
 107:              }
 108:  
 109:          }
 110:          #endregion
 111:      }
 112:  }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }And here is the code for the DataGridRecordAdorner.

   1:  using System;
   2:  using System.Collections;
   3:  using System.Windows;
   4:  using System.Windows.Controls;
   5:  using System.Windows.Documents;
   6:  using System.Windows.Media;
   7:  using System.Collections.ObjectModel;
   8:  
   9:  namespace WpfApplication1
  10:  {
  11:      /// <summary>
  12:      /// Hosts an single Label in the AdornerLayer
  13:      /// </summary>
  14:      public class DataGridRecordAdorner : Adorner
  15:      {
  16:          #region Data
  17:          private ArrayList logicalChildren;
  18:          private readonly Grid host = new Grid();
  19:          #endregion // Data
  20:  
  21:          #region Constructor
  22:  
  23:  
  24:  
  25:          public DataGridRecordAdorner(
  26:              FrameworkElement adornedCtrl, String prompt)
  27:              : base(adornedCtrl)
  28:          {
  29:  
  30:              host.Width = (double)adornedCtrl.ActualWidth;
  31:              host.Height = (double)adornedCtrl.ActualHeight;
  32:              host.VerticalAlignment = VerticalAlignment.Center;
  33:              host.HorizontalAlignment = HorizontalAlignment.Center;
  34:              host.Margin = new Thickness(0);
  35:              Label lbl = new Label();
  36:              lbl.Content = prompt;
  37:              lbl.Foreground = Brushes.White;
  38:              lbl.FontSize = 14;
  39:              lbl.FontWeight = FontWeights.Bold;
  40:              lbl.VerticalAlignment = VerticalAlignment.Center;
  41:              lbl.HorizontalAlignment = HorizontalAlignment.Center;
  42:              lbl.Margin = new Thickness(0);
  43:              host.Children.Add(lbl);
  44:              base.AddLogicalChild(host);
  45:              base.AddVisualChild(host);
  46:          }
  47:          #endregion // Constructor
  48:  
  49:          #region Measure/Arrange
  50:  
  51:          /// <summary>
  52:          /// Allows the control to determine how big it wants to be.
  53:          /// </summary>
  54:          /// <param name="constraint">A limiting size for the control.</param>
  55:          protected override Size
  56:              MeasureOverride(Size constraint)
  57:          {
  58:              return constraint;
  59:          }
  60:  
  61:          /// <summary>
  62:          /// Positions and sizes the control.
  63:          /// </summary>
  64:          /// <param name="finalSize">The actual size of the control.</param>        
  65:          protected override Size
  66:              ArrangeOverride(Size finalSize)
  67:          {
  68:              Rect rect = new Rect(new Point(), finalSize);
  69:  
  70:              host.Arrange(rect);
  71:              return finalSize;
  72:          }
  73:  
  74:          #endregion // Measure/Arrange
  75:  
  76:          #region Visual Children
  77:  
  78:          /// <summary>
  79:          /// Required for the element to be rendered.
  80:          /// </summary>
  81:          protected override int VisualChildrenCount
  82:          {
  83:              get { return 1; }
  84:          }
  85:  
  86:          /// <summary>
  87:          /// Required for the element to be rendered.
  88:          /// </summary>
  89:          protected override Visual GetVisualChild(int index)
  90:          {
  91:              if (index != 0)
  92:                  throw new ArgumentOutOfRangeException("index");
  93:  
  94:              return host;
  95:          }
  96:  
  97:          #endregion // Visual Children
  98:  
  99:          #region Logical Children
 100:  
 101:          /// <summary>
 102:          /// Required for the displayed element to 
 103:          /// inherit property values
 104:          /// from the logical tree, such as FontSize.
 105:          /// </summary>
 106:          protected override IEnumerator LogicalChildren
 107:          {
 108:              get
 109:              {
 110:                  if (logicalChildren == null)
 111:                  {
 112:                      logicalChildren = new ArrayList();
 113:                      logicalChildren.Add(host);
 114:                  }
 115:  
 116:                  return logicalChildren.GetEnumerator();
 117:              }
 118:          }
 119:  
 120:          #endregion // Logical Children
 121:      }
 122:  }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }Here are some screen shots showing this code in action, with some records within the xamDataGrid we see no label

xamGrid1

With 0 records within the xamDataGrid we see a label

xamGrid2

And finally here is the source code xamdatagridrecordsadorner.zip

Advertisements

One thought on “xamDataGrid RecordsFound Adorner

  1. Sheraz says:

    How has your experience been with infragistic WPF grid? We use winform and extensively use their grid (specially their summary feature). Do you think it does a good job performance vice?
    Thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: