DataGrid.Column MaxLength?

Jun 18, 2009 at 2:46 PM

Is there a way to set a MaxLength property on the DataGrid column?

Coordinator
Jun 19, 2009 at 5:10 PM

Do you mean set a MaxWidth on a Column?  There is a DataGridColumn.MaxWidth property.

Jun 19, 2009 at 5:17 PM

Hi Samantha,

I mean the maximum length of the text entered into the column- i.e. zip code is 5 characters. I couldn't see a way to limit this.

Coordinator
Jun 19, 2009 at 6:33 PM

Ok, I see.  You should be able to set the MaxLength property through the EditingElementStyle on your DataGridTextColumn, like so:

<DataGrid ItemsSource="...">
  <DataGrid.Columns>
    <DataGridTextColumn Header="Zip" Binding="{Binding ZipCode}">
      <DataGridTextColumn.EditingElementStyle>
        <Style TargetType="{x:Type TextBox}">
          <Setter Property="MaxLength" Value="5"/>
        </Style>
      </DataGridTextColumn.EditingElementStyle>
    </DataGridTextColumn>
  </DataGrid.Columns>
</DataGrid>

 

 

Note, however, that this will only affect data that the end user enters.  If you bind to a data which has more than 5 characters, the initial string will violate the MaxLength.  I'm assuming that the initial data is probably correct since you're binding to a zip code field, but it's something to keep in mind.

Another way to approach this is to apply a cell validation rule which checks the length of the field to the Binding on that column.  This will give you an easy mechanism to flag the field if it's invalid.  Here's an MSDN article which explains how to add a ValidationRule to a Binding: http://msdn.microsoft.com/en-us/library/system.windows.data.binding.validationrules.aspx

Thanks!
Samantha

Jun 19, 2009 at 7:06 PM

Great, thanks Samantha!

The style works great, though the ValidationRules could also be the way to go- I'll have to play around with both to see which way is best for us to go.

Is there any way I could encapsulate the EditingElementStyle of the editing element into a dependency property (or some other type of property)?

Thanks again for your help

Coordinator
Jun 23, 2009 at 8:06 PM

Yes, you should be able to create a Style DP in the code behind and encapsulate your EditingElementStyle in that property and then just bind the EditingElementStyle in your DataGridColumn to that property.  I'll warn you, though, that create Styles in the code behind is a little more painful that doing it in XAML, so you may want to just put your EditingElementStyle in a ResourceDictionary instead.

Jul 20, 2009 at 2:07 PM

Samantha

is there a other way to ensure that the user is not able to enter more than (or less than) N chars?

I use the EditingElementStyle for validation visualization, which is common for all datagrids in my app

But I want to define the MaxLength for each column separately

So how can I accomplish this?

Regards

Klaus

Jul 20, 2009 at 5:02 PM

I did this using a dependency property, then reference this property in the XAML for each column (by seeting ColumnMaxLength="10". It works like a charm

 

 


public static readonly DependencyProperty ColumnMaxLengthProperty =

   DependencyProperty.RegisterAttached(      "ColumnMaxLength",
      typeof(string),
      typeof(Helper),
      new PropertyMetadata(
          null,
          new PropertyChangedCallback(OnColumnMaxLengthChanged)));


private static void OnColumnMaxLengthChanged(DependencyObject obj,
                                            DependencyPropertyChangedEventArgs eventArg)
{
   if (!string.IsNullOrEmpty((string)eventArg.NewValue))
   {
      if (obj.GetType().IsSubclassOf(typeof(DataGridColumn)))
      {
         DataGridTextColumn textCol = obj as DataGridTextColumn;


         if (textCol != null)
         {
            /// you have to copy the existing styles to a new one,
            /// since the existing style is Sealed.                  
            Style style = textCol.EditingElementStyle;
            Style newStyle = new Style();
            foreach (Setter setter in style.Setters)
            {
               newStyle.Setters.Add(setter);
            }
 
            newStyle.Setters.Add(new Setter
            {
               Property=TextBox.MaxLengthProperty,
               Value = Convert.ToInt32(eventArg.NewValue)});
 
              textCol.EditingElementStyle = newStyle;
         }
      }
      else
      {
         throw new InvalidOperationException(
            "The Helper.ColumnMaxLength attached property " +
            "can only be used in Grid Columns.");
      }
   }
}

 

 

Jul 21, 2009 at 10:31 AM

CCusson15

thanks for your help. I do not get this to run, maybe I am missing something (I am a beginner regarding WPF)

I put the code you posted in my class "Helpers" which is contained in my wpf application project

I use the following line of xaml

<dg:DataGridTextColumn Binding="{Binding Path=ParamValue, Mode=TwoWay}" ColumnMaxLength="40"  EditingElementStyle="{StaticResource styTextBoxColumnStyleError}" Header="{Loc C_ParamValue}"/>

Maybe there is something moissing in the declaration part of my usercontrol?

Regards

Klaus

Jul 21, 2009 at 11:20 AM

CCusson15

sorry I forgot to mention the error:

  In the xaml editor: 'Property "ColumnMaxLength" not found on type "DataGridTextColumn"'

Regards

klaus

Jul 21, 2009 at 1:26 PM

Hi Klaus,

 

In your XAML, within the Page tag, you have to add an 'include' to the xmlnamespace of your helpers class, like this: (there should be some Microsoft ones in there already)

<font size="2" color="#ff0000"><font size="2" color="#ff0000">

xmlns

</font></font>
<font size="2" color="#ff0000">

 

</font>

:UIHelper="clr-namespace:Core.UIHelper"

 

Then, in the DataGridTextColumn, you need to reference the entire name of your helper class, like this:

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

<

</font></font><font size="2" color="#0000ff">

 

</font>

wpftk:DataGridTextColumn UIHelper:DPs.ColumnMaxLength="7" IsReadOnly="True" [more properties.......]

Then it should work fine for you- you won't get that compiletime error

 

Jul 23, 2009 at 9:16 PM

CCusson15

 

thanks for the help, now it compiles

But another problem arises: I already have a EditingElementStyle which is consumed by my datagridcols for displaying validation. It seems that you take that into account as you describe that the existing style is sealed, but adding the MaxLength leads to malfunctioning of my validation:

I have a animation of an error sign, a red background of the cell with an error and a toolkit decribing the error.

The animation is still there, but both the backgrounf and the toolkit is not changed in case of an error. Removing the MaxLength reanimates the validation visualization

Maybe you can tell whats wrong from my xaml

First the usercontrol snippet with the column definition:

<dg:DataGridTextColumn EditingElementStyle="{StaticResource styTextBoxColumnStyleError}" Header="{Loc C_ModuleSeqNo}" HeaderStyle="{StaticResource styHeaderFilterText}">
              <dg:DataGridTextColumn.Binding>
                <Binding Path="ModuleSeqNo">
                  <Binding.ValidationRules>
                    <validation:CellDataInfoValidationRule ValidationStep="UpdatedValue"/>
                  </Binding.ValidationRules>
                </Binding>
              </dg:DataGridTextColumn.Binding>
            </dg:DataGridTextColumn>

Second my style "styTextBoxColumnStyleError":

<Style x:Key="styTextBoxColumnStyleError" TargetType="{x:Type TextBox}">
        <Style.Triggers>
          <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="Background" Value="LightSalmon">
            </Setter>
            <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}">
            </Setter>
          </Trigger>
        </Style.Triggers>
        <Setter Property="Validation.ErrorTemplate" Value="{StaticResource ctErrorIcon_ControlTemplate}"/>
      </Style>

Interestingly the animation defined in ctErrorIcon_ControlTemplate is working, but the setting to "LightSalmon" and the output of the tooltip is missing

Any help would be really appreciated

Regards

Klaus

Jul 23, 2009 at 9:42 PM

CCusson15

I got it

I had to copy the triggers as well, now it works

Thanks for your support

Klaus

Jul 31, 2009 at 1:00 PM
Edited Jul 31, 2009 at 1:02 PM
CCusson15 wrote:

Hi Klaus,

 

In your XAML, within the Page tag, you have to add an 'include' to the xmlnamespace of your helpers class, like this: (there should be some Microsoft ones in there already)

<font size="2" color="#ff0000"><font size="2" color="#ff0000">

xmlns

</font></font>
<font size="2" color="#ff0000">

 

</font>

:UIHelper="clr-namespace:Core.UIHelper"

 

Then, in the DataGridTextColumn, you need to reference the entire name of your helper class, like this:

 

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

<

</font></font><font size="2" color="#0000ff">

 

</font>

wpftk:DataGridTextColumn UIHelper:DPs.ColumnMaxLength="7" IsReadOnly="True" [more properties.......]

Then it should work fine for you- you won't get that compiletime error

 

 

 

I've been trying to use this interesting approach, but " UIHelper:Helper.ColumnMaxLength ="7"" gives me this 2 errors:

Error    1    The attachable property 'ColumnMaxLength' was not found in type 'Helper'.

Error    2    The property 'Helper.ColumnMaxLength' does not exist in XML namespace 'clr-namespace:confapa.Helper'.

I've defined xmlns:UIHelper="clr-namespace:confapa.Helper" in the Page Tag and paste your code in a class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Windows.Controls;

namespace confapa.Helper
{
    class Helper
    {
        public static readonly DependencyProperty ColumnMaxLengthProperty =

           DependencyProperty.RegisterAttached("ColumnMaxLength",
              typeof(string),
              typeof(Helper),
              new PropertyMetadata(
                  null,
                  new PropertyChangedCallback(OnColumnMaxLengthChanged)));


        private static void OnColumnMaxLengthChanged(DependencyObject obj,
                                                    DependencyPropertyChangedEventArgs eventArg)
        {
            if (!string.IsNullOrEmpty((string)eventArg.NewValue))
            {
                if (obj.GetType().IsSubclassOf(typeof(DataGridColumn)))
                {
                    DataGridTextColumn textCol = obj as DataGridTextColumn;
                    if (textCol != null)
                    {
                        Style style = textCol.EditingElementStyle;
                        Style newStyle = new Style();
                        foreach (Setter setter in style.Setters)
                        {
                            newStyle.Setters.Add(setter);
                        }

                        newStyle.Setters.Add(new Setter
                        {
                            Property = TextBox.MaxLengthProperty,
                            Value = Convert.ToInt32(eventArg.NewValue)
                        });

                        textCol.EditingElementStyle = newStyle;
                    }
                }
                else
                {
                    throw new InvalidOperationException(
                       "The Helper.ColumnMaxLength attached property " +
                       "can only be used in Grid Columns.");
                }
            }
        }
    }

It seems I can't refer the property from the XAML, could anyone tell me what am I doing wrong?

Thanks

Aug 5, 2009 at 8:36 AM

I solved it...forgot to do the get-set functions...