Ershad
Ershad

Reputation: 957

How to set maxlength for combobox in WPF?

How do i set maxlength to combobox, which is having a style applied to it.

Thanks

Upvotes: 14

Views: 17032

Answers (6)

Tri Q Tran
Tri Q Tran

Reputation: 5690

When Using DependencyProperty, we can set the maxlength of the combo box without modifying your style/template.

public class EditableComboBox
{

    public static int GetMaxLength(DependencyObject obj)
    {
        return (int)obj.GetValue(MaxLengthProperty);
    }

    public static void SetMaxLength(DependencyObject obj, int value)
    {
        obj.SetValue(MaxLengthProperty, value);
    }

    // Using a DependencyProperty as the backing store for MaxLength.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.RegisterAttached("MaxLength", typeof(int), typeof(EditableComboBox), new UIPropertyMetadata(OnMaxLenghtChanged));

    private static void OnMaxLenghtChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var comboBox = obj as ComboBox;
        if (comboBox == null) return;

        comboBox.Loaded +=
            (s, e) =>
            {
                var textBox = comboBox.FindChild(typeof(TextBox), "PART_EditableTextBox");
                if (textBox == null) return;

                textBox.SetValue(TextBox.MaxLengthProperty, args.NewValue);
            };
    }
}

Usage example:

<ComboBox ComboboxHelper:EditableComboBox.MaxLength="50" />

Where ComboboxHelper is:

xmlns:ComboboxHelper="clr-namespace:yourNameSpace;assembly=yourAssembly"

comboBox.FindChild(...) method is posted here.

Upvotes: 27

Sasha
Sasha

Reputation: 853

I found easy solution via XAML. In comboBox resources we can set style for textbox and via setter set maxlenth.

<ComboBox Name="comboBox" Width="100" IsEditable="True">
<ComboBox.Resources>
<Style TargetType="{x:Type TextBox}"> 
    <Setter Property="MaxLength" Value="yourValue"></Setter> 
</Style>
</ComboBox.Resources>
</ComboBox>

EDIT: This works with Actipro ComboBox. For usual comboBox to make this work, have a look here

Upvotes: -1

Mr. Noob
Mr. Noob

Reputation: 146

I used PreviewKeyDown event, very simple + you can show warning or something.
Register the method below to your ComboBox.PreviewKeyDown += event,
KeyDown event will not fire if user press Space.

private void ComboBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (ComboBox.Text.Length > 19) // allow max 20 chars
    {
        if (e.Key != Key.Back) // allow removing chars
        {
            e.Handled = true; // block any additional key press if there is more than allowed max
            System.Media.SystemSounds.Beep.Play(); // optional: beep to let user know he is out of space :)
        }
    }
}

Upvotes: 1

Ershad
Ershad

Reputation: 957

This TextBox is coming null. The style given is as follows.

<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="{Binding Path=(local:ToggleComboBox.Width),
                     RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}" />
            </Grid.ColumnDefinitions>
            <Border x:Name="Border" 
                    Grid.Column="1"
                    CornerRadius="2"
                    Background="#CCFFCC"
                    BorderBrush="#000080"
                    BorderThickness="4" />

            <Border Grid.Column="0"
                    CornerRadius="8,8,8,8" 
                    Margin="0" 
                    Background="#CCFFCC" 
                    BorderBrush="#000080"
                    BorderThickness="4,4,4,4" />

            <Image x:Name="Arrow"
                   Grid.Column="1"     
                   Source="Arrow.png" Margin="4,4,4,4"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"/>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="ToggleButton.IsMouseOver" Value="true">
                <Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" />
            </Trigger>
            <Trigger Property="ToggleButton.IsChecked" Value="true">
                <Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
            </Trigger>
            <Trigger Property="IsEnabled" Value="False">
                <Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
                <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
                <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
                <!--<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource DisabledForegroundBrush}" />-->
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

    <ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
        <Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
    </ControlTemplate>


    <Style x:Key="ComboBoxStyle" TargetType="ComboBox">
        <Setter Property="SnapsToDevicePixels" Value="true"/>
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
        <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
        <Setter Property="MinWidth" Value="120"/>
        <Setter Property="MinHeight" Value="20"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ComboBox">
                    <Grid>
                        <ToggleButton Name="ToggleButton" 
                                      Template="{StaticResource ComboBoxToggleButton}" 
                                      Grid.Column="2" 
                                      Focusable="false"
                                      IsChecked="{Binding Path=IsDropDownOpen,
                                                          Mode=TwoWay,
                                                          RelativeSource={RelativeSource TemplatedParent}}"
                                      ClickMode="Press"/>

                        <ContentPresenter Name="ContentSite"
                                          IsHitTestVisible="False" 
                                          Content="{TemplateBinding SelectionBoxItem}"
                                          ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
                                          ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
                                          Margin="9,2,28,2"
                                          VerticalAlignment="Center"
                                          HorizontalAlignment="Left" />

                        <TextBox x:Name="PART_EditableTextBox"
                                 Style="{x:Null}" 
                                 Template="{StaticResource ComboBoxTextBox}" 
                                 HorizontalAlignment="Left" 
                                 VerticalAlignment="Center" 
                                 Margin="3,3,23,3"
                                 Focusable="True" 
                                 Background="Transparent"
                                 Visibility="Hidden"
                                 IsReadOnly="{TemplateBinding IsReadOnly}"/>

                        <Popup Name="Popup"
                               Placement="Bottom"
                               IsOpen="{TemplateBinding IsDropDownOpen}"
                               AllowsTransparency="True" 
                               Focusable="False"
                               PopupAnimation="Slide">

                            <Grid Name="DropDown"
                                  SnapsToDevicePixels="True"             
                                  MinWidth="{TemplateBinding ActualWidth}"
                                  MaxHeight="{TemplateBinding MaxDropDownHeight}">

                                <Border x:Name="DropDownBorder"
                                        Background="#CCFFCC" 
                                        BorderBrush="#000080"
                                        BorderThickness="2"/>

                                <ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
                                    <ScrollViewer.Resources>
                                        <sys:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">25</sys:Double>
                                    </ScrollViewer.Resources>                                    
                                    <StackPanel IsItemsHost="True" />
                                </ScrollViewer>
                            </Grid>
                        </Popup>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="HasItems" Value="false">
                            <Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
                        </Trigger>
                        <Trigger Property="IsGrouping" Value="true">
                            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                        </Trigger>
                        <Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
                            <Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
                            <Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
                        </Trigger>
                        <Trigger Property="IsEditable" Value="true">
                            <Setter Property="IsTabStop" Value="false"/>
                            <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
                            <Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemContainerStyle" >
            <Setter.Value>
                <Style TargetType="{x:Type ComboBoxItem}">
                    <Setter Property="FontSize" Value="20" />
                </Style>
            </Setter.Value>
        </Setter>
    </Style>

Upvotes: 0

biju
biju

Reputation: 18040

Or you can use the GotFocus or Loaded event of the combobox for setting the maxlength.If the maxlength doest change too much during runtime you can use loaded event or else use gotfocus event

<ComboBox Height="30" IsEditable="True" Loaded="ComboBox_Loaded"/>

and in the respective event...

   var obj = (ComboBox)sender;
    if (obj != null)
    {
        var myTextBox = (TextBox)obj.Template.FindName("PART_EditableTextBox",obj);
        if (myTextBox != null)
        {
            myTextBox.MaxLength = maxLength;
        }
    }

Upvotes: 9

Rap
Rap

Reputation: 7292

You are correct. There is a maxlength for a Textbox, but not for a combobox. You have to roll your own using a Textbox as an intermediary. Here's some code:

public int MaxLength {get; set;}
protected override void OnGotFocus(System.Windows.RoutedEventArgs e)
{
    base.OnGotFocus(e);
    TextBox thisTextBox = (TextBox)base.GetTemplateChild("PART_EditableTextBox");
    if (thisTextBox != null)
        thisTextBox.MaxLength = MaxLength;
}

Upvotes: 2

Related Questions