问题描述:

I need to force uppercase input inside AutoCompleteBox in Silverlight 4 app.

In TextBox this could be done by replacing Text property on KeyDown event like:

 control.Text += enteredChar;

control.Select(control.Text.Length, 0); //To maintain caret position

However AutoCompleteBox doesn't provide text selection function, and I found no way to move caret to string end.

网友答案:

You need to change AutoCompleteBox template and add UpperCaseBehavior to the TextBox within:

<TextBox x:Name="Text" ...>
    <i:Interaction.Behaviors>
        <behaviors:UpperCaseBehavior/>
    </i:Interaction.Behaviors>
</TextBox>

where UpperCaseBehavior is:

public class UpperCaseBehavior: Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.TextChanged += AssociatedObject_TextChanged;
    }

    private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs args)
    {
        var selectionStart = AssociatedObject.SelectionStart;
        var selectionLength = AssociatedObject.SelectionLength;

        AssociatedObject.Text = AssociatedObject.Text.ToUpper();

        AssociatedObject.SelectionStart = selectionStart;
        AssociatedObject.SelectionLength = selectionLength;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.TextChanged -= AssociatedObject_TextChanged;
        base.OnDetaching();
    }
}
网友答案:

You could use binding and convert the typed value to uppercase immediately. Add a custom style to have the textchanged event. I tested this, so if you need I can send you a sample if you don't manage to get it working.

XAML:

Add a resource:

<Style x:Key="AutoCompleteBoxStyle1" TargetType="sdk:AutoCompleteBox">
                <Setter Property="IsTabStop" Value="False"/>
                <Setter Property="Padding" Value="2"/>
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="BorderBrush">
                    <Setter.Value>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#FFA3AEB9" Offset="0"/>
                            <GradientStop Color="#FF8399A9" Offset="0.375"/>
                            <GradientStop Color="#FF718597" Offset="0.375"/>
                            <GradientStop Color="#FF617584" Offset="1"/>
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
                <Setter Property="Background" Value="#FFFFFFFF"/>
                <Setter Property="Foreground" Value="#FF000000"/>
                <Setter Property="MinWidth" Value="45"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="sdk:AutoCompleteBox">
                            <Grid Opacity="{TemplateBinding Opacity}">
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup x:Name="PopupStates">
                                        <VisualStateGroup.Transitions>
                                            <VisualTransition GeneratedDuration="0:0:0.1" To="PopupOpened"/>
                                            <VisualTransition GeneratedDuration="0:0:0.2" To="PopupClosed"/>
                                        </VisualStateGroup.Transitions>
                                        <VisualState x:Name="PopupOpened">
                                            <Storyboard>
                                                <DoubleAnimation To="1.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PopupBorder"/>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="PopupClosed">
                                            <Storyboard>
                                                <DoubleAnimation To="0.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PopupBorder"/>
                                            </Storyboard>
                                        </VisualState>
                                    </VisualStateGroup>
                                    <VisualStateGroup x:Name="ValidationStates">
                                        <VisualState x:Name="Valid"/>
                                        <VisualState x:Name="InvalidUnfocused">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement">
                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                        <DiscreteObjectKeyFrame.Value>
                                                            <Visibility>Visible</Visibility>
                                                        </DiscreteObjectKeyFrame.Value>
                                                    </DiscreteObjectKeyFrame>
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="InvalidFocused">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement">
                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                        <DiscreteObjectKeyFrame.Value>
                                                            <Visibility>Visible</Visibility>
                                                        </DiscreteObjectKeyFrame.Value>
                                                    </DiscreteObjectKeyFrame>
                                                </ObjectAnimationUsingKeyFrames>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen" Storyboard.TargetName="validationTooltip">
                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                        <DiscreteObjectKeyFrame.Value>
                                                            <System:Boolean>True</System:Boolean>
                                                        </DiscreteObjectKeyFrame.Value>
                                                    </DiscreteObjectKeyFrame>
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </VisualState>
                                    </VisualStateGroup>
                                </VisualStateManager.VisualStateGroups>
                                <TextBox x:Name="Text" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" IsTabStop="True" Margin="0" Padding="{TemplateBinding Padding}" Style="{TemplateBinding TextBoxStyle}" SelectionChanged="Text_SelectionChanged"/>
                                <Border x:Name="ValidationErrorElement" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1" Visibility="Collapsed">
                                    <ToolTipService.ToolTip>
                                        <ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource CommonValidationToolTipTemplate}">
                                            <ToolTip.Triggers>
                                                <EventTrigger RoutedEvent="Canvas.Loaded">
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="validationTooltip">
                                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                                    <DiscreteObjectKeyFrame.Value>
                                                                        <System:Boolean>true</System:Boolean>
                                                                    </DiscreteObjectKeyFrame.Value>
                                                                </DiscreteObjectKeyFrame>
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger>
                                            </ToolTip.Triggers>
                                        </ToolTip>
                                    </ToolTipService.ToolTip>
                                    <Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">
                                        <Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/>
                                        <Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/>
                                    </Grid>
                                </Border>
                                <Popup x:Name="Popup">
                                    <Grid Opacity="{TemplateBinding Opacity}">
                                        <Border x:Name="PopupBorder" BorderThickness="0" Background="#11000000" HorizontalAlignment="Stretch" Opacity="0">
                                            <Border.RenderTransform>
                                                <TranslateTransform X="1" Y="1"/>
                                            </Border.RenderTransform>
                                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="0" HorizontalAlignment="Stretch" Opacity="1.0" Padding="0">
                                                <Border.Background>
                                                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                                        <GradientStop Color="#FFDDDDDD" Offset="0"/>
                                                        <GradientStop Color="#AADDDDDD" Offset="1"/>
                                                    </LinearGradientBrush>
                                                </Border.Background>
                                                <Border.RenderTransform>
                                                    <TransformGroup>
                                                        <TranslateTransform X="-1" Y="-1"/>
                                                    </TransformGroup>
                                                </Border.RenderTransform>
                                                <ListBox x:Name="Selector" BorderThickness="0" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" ScrollViewer.HorizontalScrollBarVisibility="Auto" ItemTemplate="{TemplateBinding ItemTemplate}" ItemContainerStyle="{TemplateBinding ItemContainerStyle}" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
                                            </Border>
                                        </Border>
                                    </Grid>
                                </Popup>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

Add your AutoCompleteBox and reference the previous style:

<sdk:AutoCompleteBox Width="169" x:Name="txtSearchBox" Text="{Binding TypedText, Mode=TwoWay}" Style="{StaticResource AutoCompleteBoxStyle1}" />

Code Behind:

Bind the typed text:

private string _typedText;
public string TypedText
{
    get { return _typedText; }
    set
    {
        _typedText = value.ToUpper();
        NotifyPropertyChanged("TypedText");
    }
}

The TextSelection event:

private void Text_SelectionChanged(object sender, System.Windows.RoutedEventArgs e)
        {
            TextBox tb = sender as TextBox;
            if (tb != null && !String.IsNullOrEmpty(TypedText) && tb.SelectionStart != TypedText.Length)
            {
                tb.SelectionStart = TypedText.Length;
                tb.SelectionLength = 0;
            }
        }

HTH

网友答案:

It isn't perfect, but it works! on lost focus event put the text in upper case

<pre>
private void AutoCompleteTextBox_LostFocus(object sender, RoutedEventArgs e)
{
  var a = (AutoCompleteTextBox)sender;
  a.Text = a.Text.ToUpper();
}
</pre>
网友答案:

I ended up, creating font with only capital latters and using it.

网友答案:

MSDN: AutoCompleteBox Styles and Templates

Basically just use a style setter on the TextBox.CharacterCasing property as follows:

    <my:AutoCompleteBox x:Name="autoCompleteBox1">
        <my:AutoCompleteBox.TextBoxStyle>
            <Style TargetType="TextBox">
                <Setter Property="CharacterCasing" Value="Upper" />
            </Style>
        </my:AutoCompleteBox.TextBoxStyle>
    </my:AutoCompleteBox>

This avoids the hassle of then having to hack a solution to the caret position problem when adjusting the case of the text.

There are other options for where and how to setup the Style and Setter of course (I've forgotten the ins and outs but the above seemed to get the job done)

NB: I'm using this in WPF .Net v4.0, with an AutoCompleteBox that does an async list populate (no filtering is done by the control).

相关阅读:
Top