UWP - 如何实现完全自定义的TextBox

时间:2016-11-15 08:52:35

标签: c# xaml user-controls uwp uwp-xaml

我想创建一个这样的自定义TextBox:

enter image description here

我知道我可以通过编辑模板和样式来完成大部分操作,但我希望能够从XAML中获取符号值,如下所示:

<TextBoxWithSymbol FontSize="..." FontFamily="..." PlaceholderText="Write something here..." SymbolCode="&#xE102;" />

如果我使用UserControl,我想我应该实现许多TextBox属性,并且也无法在UserControl中继承TextBox本身。

有什么建议吗?

P.S:

我在@Bart说过,但是当我在XAML页面中使用我的控件时,它显示为普通的TextBox。以下是Generic.xaml的代码:

<Style TargetType="local:TextBoxWithSymbol" >
        <Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}"/>
        <Setter Property="MinHeight" Value="{ThemeResource TextControlThemeMinHeight}"/>
        <Setter Property="Foreground" Value="{Binding FallbackValue=Gray}"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="SelectionHighlightColor" Value="{ThemeResource TextControlSelectionHighlightColor}"/>
        <Setter Property="BorderBrush" Value="{Binding FallbackValue=DarkGray}" />
        <Setter Property="BorderThickness" Value="0,0,0,1"/>
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
        <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
        <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto"/>
        <Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
        <Setter Property="Padding" Value="{ThemeResource TextControlThemePadding}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TextBoxWithSymbol">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="HeaderContentPresenter">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlHeaderForegroundDisabled}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding FallbackValue=Gray}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundDisabled}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextContentPresenter">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundDisabled}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBorderBrushPointerOver}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextContentPresenter">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundPointerOver}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlForegroundPointerOver}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextContentPresenter">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlPlaceholderForegroundFocused}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderThickness" Storyboard.TargetName="BorderElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="0,0,0,2" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" Storyboard.TargetName="BorderElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="0,0,0,-1" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding FallbackValue=LightGreen}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding FallbackValue=Gray}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="RequestedTheme" Storyboard.TargetName="ContentElement">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Light"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="BorderElement" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Row="1" Grid.RowSpan="1"/>
                        <ContentPresenter x:Name="HeaderContentPresenter" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Foreground="{ThemeResource TextControlHeaderForeground}" FontWeight="Normal" Margin="0,0,0,8" Grid.Row="0" Visibility="Collapsed" x:DeferLoadStrategy="Lazy"/>
                        <ScrollViewer x:Name="ContentElement" AutomationProperties.AccessibilityView="Raw" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsTabStop="False" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Grid.Row="1" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="Disabled"/>
                        <ContentControl VerticalAlignment="Center" x:Name="PlaceholderTextContentPresenter" Content="{TemplateBinding PlaceholderText}" Foreground="{ThemeResource TextControlPlaceholderForeground}" IsHitTestVisible="False" IsTabStop="False" Margin="{TemplateBinding BorderThickness}" Padding="5,0,0,0" Grid.Row="1"/>
                        <TextBlock x:Name="SymbolElement" Grid.Column="1" Grid.Row="1" Text="{TemplateBinding SymbolText}" FontFamily="{TemplateBinding SymbolFontFamily}" FontSize="{TemplateBinding SymbolFontSize}" Margin="12,0,0,0" VerticalAlignment="Center" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

和TextBoxWithSymbol.cs:

public FontFamily SymbolFontFamily
        {
            get { return (FontFamily)GetValue(SymbolFontFamilyProperty); }
            set { SetValue(SymbolFontFamilyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SymbolCode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SymbolFontFamilyProperty =
            DependencyProperty.Register("SymbolFontFamily", typeof(FontFamily ), typeof(TextBoxWithSymbol), new PropertyMetadata(new FontFamily("Segoe MDL2 Assets"), SymbolFontFamilyPropertyChanged));

        private static void SymbolFontFamilyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var owner = d as TextBoxWithSymbol;
        }

        public string SymbolText
        {
            get { return (string)GetValue(SymbolTextProperty); }
            set { SetValue(SymbolTextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SymbolCode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SymbolTextProperty =
            DependencyProperty.Register("SymbolText", typeof(string), typeof(TextBoxWithSymbol), new PropertyMetadata("\uE001", SymbolTextPropertyChanged));

        private static void SymbolTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var owner = d as TextBoxWithSymbol;
        }



        public double SymbolFontSize
        {
            get { return (double)GetValue(SymbolFontSizeProperty); }
            set { SetValue(SymbolFontSizeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SymbolFontSize.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SymbolFontSizeProperty =
            DependencyProperty.Register("SymbolFontSize", typeof(double), typeof(TextBoxWithSymbol), new PropertyMetadata(20, SymbolFontSizePropertyChanged));

        private static void SymbolFontSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var owner = d as TextBoxWithSymbol;
        }

P.S:

它在我运行应用程序时有效,但在设计时我无法看到我的控件的外观(我的意思是在MainPage.xaml这样的页面中)。有没有办法让设计时间延长?

1 个答案:

答案 0 :(得分:2)

UserControl是其他控件的包装器。您需要的是Templated Control

enter image description here

TextBox派生控件,并为SymbolCode或您想要的任何其他内容添加自己的依赖项属性。

public sealed class CustomControl1 : TextBox
{
    public CustomControl1()
    {
        this.DefaultStyleKey = typeof(CustomControl1);
    }
}

最后更改Generic.xaml中的模板以满足您的需求。可能最容易从TextBox模板开始,然后从那里开始工作。