silverlight带水印的自定义TextBox控件(版本2)

之前那个版本《silverlight-带水印的TextBox》不得不说是相当失败的,起码我是这样理解的。其实我一心想把这个给实现了,但是不得不承认自身技术上的缺陷。经过一番尝试和折腾,有了下面这个版本。

两个版本的区别:

其实是有本质的区别的。

之前那个版本只能设置“文本水印”,相当有局限性。现在的版本是可以自定义水印内容的。譬如,可以为button,rectangle,ellipsed... 

1.先新建一个“silverlight 模板化控件”,取名随意,此处为SuperText

2.修改继承的类Contol为TextBox

3.修改TextBox模板

控件SuperTextBox的模板,样式都是保存在一个叫“Generic.xaml”文件里面的。在第一次新建“silverlight 模板化控件”的时候,这个文件会自动产生。这里将TextBox的模板添加进入,并修改。

完整的

完整的Generic.xaml
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:local="clr-namespace:TextBoxWaterMark">


    <Style TargetType="local:SuperTextBox">

        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Background" Value="#FFFFFFFF"/>
        <Setter Property="Foreground" Value="#FF000000"/>
        <Setter Property="Padding" Value="2"/>
        <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="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:SuperTextBox">
                    <Grid x:Name="RootElement">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="MouseOverBorder" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="#FF99C1E2" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="ReadOnly">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="ReadOnlyVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unfocused">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="0" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="ValidationStates">
                                <VisualState x:Name="Valid"/>
                                <VisualState x:Name="InvalidUnfocused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="InvalidFocused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <sys:Boolean>True</sys:Boolean>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>

                            <VisualStateGroup x:Name="WatermarkDisplayed">
                                <VisualState x:Name="Hidden">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="watermarkContent" Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0" />
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Shown">
                                    <Storyboard>
                                        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="watermarkContent" Storyboard.TargetProperty="(UIElement.Opacity)">
                                            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1" />
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            
                        </VisualStateManager.VisualStateGroups>
                        
                        <Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
                            <Grid>
                                
                                <UserControl x:Name="watermarkContent" Content="{TemplateBinding Watermark}"/>
                                
                                <Border x:Name="ReadOnlyVisualElement" Opacity="0" Background="#5EC9C9C9"/>
                                <Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent">
                                    <ScrollViewer x:Name="ContentElement" Padding="{TemplateBinding Padding}" BorderThickness="0" IsTabStop="False"/>
                                </Border>
                            </Grid>
                        </Border>
                        <Border x:Name="DisabledVisualElement" Background="#A5F7F7F7" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}" Opacity="0" IsHitTestVisible="False"/>
                        <Border x:Name="FocusVisualElement" BorderBrush="#FF6DBDD1" BorderThickness="{TemplateBinding BorderThickness}" Margin="1" Opacity="0" IsHitTestVisible="False"/>
                        <Border x:Name="ValidationErrorElement" BorderThickness="1" CornerRadius="1" BorderBrush="#FFDB000C" Visibility="Collapsed">
                            <Grid Width="12" Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Background="Transparent">
                                <Path Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C"/>
                                <Path Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff"/>
                            </Grid>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

    </Style>
</ResourceDictionary>

 在上面的"Generic.xaml"文件的SuperTextBox模板中修改新增了一下内容

  • 新增一个UserControl,即水印内容。

取名随意,这里为“watermarkContent”,并且绑定Content属性为“WaterMark”

<UserControl x:Name="watermarkContent" Content="{TemplateBinding Watermark}"/>
  •  增加两个状态

状态为了控制水印是否出现。其实本质是调节水印的透明度。

<VisualStateGroup x:Name="WatermarkDisplayed">
    <VisualState x:Name="Hidden">
        <Storyboard>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="watermarkContent" Storyboard.TargetProperty="(UIElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </VisualState>
    <VisualState x:Name="Shown">
        <Storyboard>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="watermarkContent" Storyboard.TargetProperty="(UIElement.Opacity)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </VisualState>
</VisualStateGroup>

4.在托管代码中

  • 因为模板中绑定了一个新的属性WaterMark,所以需要在托管代码进行注册。并且用属性Watermark保存。
public object Watermark
{
    get { return base.GetValue(WatermarkProperty) as object; }
    set { base.SetValue(WatermarkProperty, value); }
}

//向空间增加property 
public static readonly DependencyProperty WatermarkProperty =
DependencyProperty.Register("Watermark", typeof(object), typeof(SuperTextBox), new PropertyMetadata(null));
  • 为了控制水印状态需要增加一个TextChanged事件。
public SuperTextBox()
{
    this.DefaultStyleKey = typeof(SuperTextBox);
    TextChanged += new TextChangedEventHandler(SuperTextBox_TextChanged);
}

void SuperTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    TextBox tb = (TextBox)sender;
    if (tb.Text.Length > 0)
    {
        System.Windows.VisualStateManager.GoToState(tb, "Hidden", false);
    }
    else
    {
        System.Windows.VisualStateManager.GoToState(tb, "Shown", false);
    } 
}
  • 完整托管代码
完整的SuperTextBox托管代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace TextBoxWaterMark
{
    public class SuperTextBox : TextBox
    {

        public object Watermark
        {
            get { return base.GetValue(WatermarkProperty) as object; }
            set { base.SetValue(WatermarkProperty, value); }
        }

        //向空间增加property 瓶颈所在
        public static readonly DependencyProperty WatermarkProperty =
        DependencyProperty.Register("Watermark", typeof(object), typeof(SuperTextBox), new PropertyMetadata(null));


        public SuperTextBox()
        {
            this.DefaultStyleKey = typeof(SuperTextBox);
            TextChanged += new TextChangedEventHandler(SuperTextBox_TextChanged);
        }

        void SuperTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox tb = (TextBox)sender;
            if (tb.Text.Length > 0)
            {
                System.Windows.VisualStateManager.GoToState(tb, "Hidden", false);
            }
            else
            {
                System.Windows.VisualStateManager.GoToState(tb, "Shown", false);
            } 
        }

        public override void  OnApplyTemplate()
        {
            base.OnApplyTemplate();
        }

    }

}

5.调用

<local:SuperTextBox Height="20">
                <local:SuperTextBox.Watermark>
                    <StackPanel Orientation="Horizontal" Opacity="0.4">
                        <Rectangle Fill="Red" Width="10" Height="10"/>
                        <TextBlock Text="我是一个水印"/>
                    </StackPanel>
                </local:SuperTextBox.Watermark>
            </local:SuperTextBox>

需加上命名空间local,local指向的是SuperTextBox所在的命名空间。

6.效果

参考资料:《[控件问题] TextBox控件的Watermark问题变通解决方法
silverlight-带水印的TextBox
 
人生苦短,虚心求教
原文地址:https://www.cnblogs.com/rond/p/2652271.html