WPF自定义TextBox(可选:图片, 占位符)

参考改版后的:http://blog.csdn.net/oneonce/article/details/77072894


有点问题:背景设置不生效,目前只能用白色(默认)背景微笑,求指点



public class ImageTextBox : TextBox
    {
        private const double PLACEHOLDER_FONTSIZE_DEF = 10.0;

        private const double NUMERATOR = 1.0;
        private const double DENOMINATOR = 5.0;
        private const double IMAGE_MARGIN_LEFT = 3.0;
        private const double IMAGE_MARGIN_RATE= -NUMERATOR / DENOMINATOR;
        private const double IMAGE_MARGIN_TOP = 3.0;
        private const double IMAGE_MARGIN_BOTTOM = 3.0;
        private const double IMAGE_MARGIN_RIGHT = 3.0;
        private const double IMAGE_MARGIN_TEXT = 2.0;
        private const double CORNER_RADIUS = 0.0;

        private TextBox mInputBox = null;
        private Thickness mInputBoxMargin = new Thickness(0, IMAGE_MARGIN_TOP, 0 , IMAGE_MARGIN_BOTTOM);
        private double mInputBoxWidth = 0.0;
        private Thickness mLeftImageMargin = new Thickness(CORNER_RADIUS * (1 + IMAGE_MARGIN_LEFT), IMAGE_MARGIN_TOP, IMAGE_MARGIN_TEXT, IMAGE_MARGIN_BOTTOM);
        private Size mLeftImageSize = new Size(0, 0);
        private double mPlaceHolderFontSize = PLACEHOLDER_FONTSIZE_DEF;

        static ImageTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageTextBox), new FrameworkPropertyMetadata(typeof(ImageTextBox)));
        }

        public ImageTextBox()
        {
        }

        public override void OnApplyTemplate()
        {
            mInputBox = GetTemplateChild("TEXTBOX_PART") as TextBox;

            base.OnApplyTemplate();
        }

        public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(nameof(Image), typeof(ImageSource), typeof(ImageTextBox),
                                                                                                                                                                    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, ImageSourceChanged));
        public ImageSource Image
        {
            get { return (ImageSource)GetValue(ImageProperty); }
            set { SetValue(ImageProperty, value); }
        }

        public static readonly DependencyProperty PlaceHolderProperty = DependencyProperty.Register(nameof(PlaceHolder), typeof(string), typeof(ImageTextBox), new PropertyMetadata(""));
        public string PlaceHolder
        {
            get { return (string)GetValue(PlaceHolderProperty); }
            set { SetValue(PlaceHolderProperty, value); }
        }

        public double PlaceHolderFontSize
        {
            get {
                if (PLACEHOLDER_FONTSIZE_DEF == mPlaceHolderFontSize)
                {
                    mPlaceHolderFontSize = FontSize * 3.0 / 5.0;
                }
                return mPlaceHolderFontSize;
            }
        }

        public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(nameof(CornerRadius), typeof(string), typeof(ImageTextBox), new PropertyMetadata(CORNER_RADIUS.ToString()));
        public string CornerRadius
        {
            get { return (string)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }

        //public static readonly DependencyProperty InputBoxMarginProperty = DependencyProperty.Register(nameof(InputBoxMargin), typeof(Thickness), typeof(ImageTextBox), new PropertyMetadata(new Thickness(0, 0, 0, 0)));

        public Thickness InputBoxMargin
        {
            //get { return (Thickness)GetValue(InputBoxMarginProperty); }
            //set { SetValue(InputBoxMarginProperty, value); }

            get
            {
                double cornerRadius = double.Parse(CornerRadius);
                double lr= cornerRadius * (1 + IMAGE_MARGIN_RATE);

                if (0 == mInputBoxMargin.Left)
                {
                    if (0 == cornerRadius)
                    {
                        mInputBoxMargin.Left = IMAGE_MARGIN_LEFT;
                    }
                    else
                    {
                        mInputBoxMargin.Left = lr;
                    }
                }

                if (0 == mInputBoxMargin.Right)
                {
                    if (0 == cornerRadius)
                    {
                        mInputBoxMargin.Right = IMAGE_MARGIN_RIGHT;
                    }
                    else
                    {
                        mInputBoxMargin.Right = lr;
                    }
                }

                return mInputBoxMargin;
            }
        }

        public double InputBoxWidth
        {
            get
            {
                double cornerRadius = double.Parse(CornerRadius);
                double lr = cornerRadius * (1 + IMAGE_MARGIN_RATE);

                if (double.IsNaN(Width))
                {
                    mInputBoxWidth = 10;
                }
                else
                {
                    if (0 == mInputBoxWidth)
                    {
                        mInputBoxWidth = Width - 2 *lr;
                    }
                }

                return mInputBoxWidth;
            }
        }

        public Thickness LeftImageMargin
        {
            get
            {
                return mLeftImageMargin;
            }
        }

        public Size LeftImageSize
        {
            get
            {
                return mLeftImageSize;
            }
        }

        private static void ImageSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ImageTextBox thisImageTextBox = null;
            ImageSource imageSource = null;

            if (null != sender)
            {
                thisImageTextBox = sender as ImageTextBox;
                if (null == thisImageTextBox)
                {
                    return;
                }
            }

            if (e.NewValue is ImageSource)
            {
                imageSource = e.NewValue as ImageSource;
                if (null == imageSource)
                {
                    return;
                }
            }

            double cornerRadius = double.Parse((string)thisImageTextBox.GetValue(CornerRadiusProperty));
            if (0 == cornerRadius)
            {
                thisImageTextBox.mLeftImageMargin.Left = IMAGE_MARGIN_LEFT;
            }
            else
            {
                thisImageTextBox.mLeftImageMargin.Left = cornerRadius * (1 + IMAGE_MARGIN_RATE);
                thisImageTextBox.mInputBoxMargin.Right = cornerRadius * (1 + IMAGE_MARGIN_RATE) + IMAGE_MARGIN_TEXT;
            }

            if (0 == thisImageTextBox.mInputBoxMargin.Left)
            {
                thisImageTextBox.mInputBoxMargin.Left = thisImageTextBox.mLeftImageMargin.Left  + imageSource.Width + thisImageTextBox.mLeftImageMargin.Right;
            }
            
            thisImageTextBox.mInputBoxWidth = thisImageTextBox.Width - thisImageTextBox.mInputBoxMargin.Left - thisImageTextBox.mInputBoxMargin.Right ;

            thisImageTextBox.mLeftImageSize.Width = imageSource.Width;
            thisImageTextBox.mLeftImageSize.Height = imageSource.Height;
        }
    }


<Style TargetType="{x:Type ctrls:ImageTextBox}">
        <Setter Property="Foreground" Value="Black"/>
        <Setter Property="Background" Value="White"/>
        <Setter Property="BorderBrush" Value="#ff2D2D30"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="CaretBrush" Value="Black"/>
        <Setter Property="Opacity" Value="1"/>
        <Setter Property="CornerRadius" Value="0"/>
        <Setter Property="FontSize" Value="18"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ctrls:ImageTextBox}">
                    <Grid x:Name="ROOT_PART" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <Border x:Name="mask"
                                Opacity="{TemplateBinding Opacity}"
                                Background="White"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                CornerRadius="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}}" />
                        <Border/>
                        <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                            <Image Panel.ZIndex="2"
                                   Margin="{Binding LeftImageMargin, RelativeSource={RelativeSource TemplatedParent}}"
                                   Width="{Binding LeftImageSize.Width, RelativeSource={RelativeSource TemplatedParent}}"
                                   Height="{Binding LeftImageSize.Height, RelativeSource={RelativeSource TemplatedParent}}"
                                   Source="{Binding Image, RelativeSource={RelativeSource TemplatedParent}}"
                                   HorizontalAlignment="Left" VerticalAlignment="Center"/>
                            <TextBox x:Name="TEXTBOX_PART" Panel.ZIndex="1"
                                     Foreground="{TemplateBinding Foreground}"
                                     RenderOptions.ClearTypeHint="Enabled" 
                                     SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                     HorizontalAlignment="Left" VerticalAlignment="Stretch"
                                     Width="{Binding InputBoxWidth, RelativeSource={RelativeSource TemplatedParent}}"
                                     Margin="{Binding InputBoxMargin, RelativeSource={RelativeSource TemplatedParent}}"
                                     FontSize="{TemplateBinding FontSize}" 
                                     BorderThickness="0"
                                     VerticalContentAlignment="Center"
                                     TextAlignment="{TemplateBinding TextAlignment}"
                                     CaretBrush="{Binding CaretBrush, RelativeSource={RelativeSource  AncestorType={x:Type ctrls:ImageTextBox}}}"
                                     ToolTip="{TemplateBinding ToolTip}"
                                     Text="{Binding Path=Text, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">

                                <TextBox.Resources>
                                    <VisualBrush x:Key="PLACEHOLDER_PART" TileMode="None" Opacity="1" Stretch="None" AlignmentX="Left">
                                        <VisualBrush.Visual>
                                            <TextBox Opacity="1"  Foreground="LightGray"
                                                Text="{Binding Path=PlaceHolder, RelativeSource={RelativeSource  AncestorType={x:Type ctrls:ImageTextBox}}}"
                                                     Background="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}"
                                                    FontSize="{Binding PlaceHolderFontSize, RelativeSource={RelativeSource  AncestorType={x:Type ctrls:ImageTextBox}}}"
                                                     Margin="{Binding InputBoxMargin, RelativeSource={RelativeSource TemplatedParent}}"
                                                     BorderThickness="0" BorderBrush="Transparent"
                                                     Width="{Binding Width, ElementName=TEXTBOX_PART}"/>
                                        </VisualBrush.Visual>
                                    </VisualBrush>
                                </TextBox.Resources>

                                <TextBox.Style>
                                    <Style TargetType="TextBox">
                                        <Style.Triggers>
                                            <Trigger Property="Text" Value="{x:Null}">
                                                <Setter Property="Background" Value="{StaticResource PLACEHOLDER_PART}"/>
                                            </Trigger>
                                            <Trigger Property="Text" Value="">
                                                <Setter Property="Background" Value="{StaticResource PLACEHOLDER_PART}"/>
                                            </Trigger>
                                            <!--<DataTrigger Binding="{Binding Path=Text,RelativeSource={RelativeSource AncestorType={x:Type TextBox}},Converter={StaticResource isNullConverter},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Value="False">
                                                    <Setter Property="Background" Value="Transparent"/>
                                                </DataTrigger>-->

                                            <!--<Trigger Property="IsFocused" Value="False">
                                                <Setter Property="Background" Value="Transparent" />
                                            </Trigger>-->

                                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Text.Length}" Value="0">
                                                <Setter Property="Background" Value="{StaticResource PLACEHOLDER_PART}"/>
                                            </DataTrigger>
                                            <!--<MultiDataTrigger>
                                                <MultiDataTrigger.Conditions>
                                                    <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self},Path=Text.Length}" Value="0"/>
                                                    <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self},Path=IsFocused}" Value="False"/>
                                                </MultiDataTrigger.Conditions>
                                                <MultiDataTrigger.Setters>
                                                    <Setter Property="Background" Value="{StaticResource PLACEHOLDER_PART}"/>
                                                </MultiDataTrigger.Setters>
                                            </MultiDataTrigger>-->

                                            <!--<Trigger Property="IsKeyboardFocused" Value="true">
                                                <Setter Property="Background" Value="Transparent" />
                                            </Trigger>-->
                                        </Style.Triggers>
                                    </Style>
                                </TextBox.Style>
                            </TextBox>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


使用1:

<ctrls:ImageTextBox x:Name="tbUserName" Width="300" Height="50"
        PlaceHolder="请输入用户名"
        TextChanged="tbUserName_TextChanged"/>


使用2:

<ctrls:ImageTextBox x:Name="tbUserName" Width="300" Height="50"
        CornerRadius="20"
        PlaceHolder="请输入用户名"
        TextChanged="tbUserName_TextChanged"/>

使用3:

<ctrls:ImageTextBox x:Name="tbUserName" Width="300" Height="50"
        PlaceHolder="请输入用户名"
        Image="Resources/Images/logo.jpg"
        TextChanged="tbUserName_TextChanged"/>


使用4:

<ctrls:ImageTextBox x:Name="tbUserName" Width="300" Height="50"
        CornerRadius="20"
        PlaceHolder="请输入用户名"
        Image="Resources/Images/logo.jpg"
        TextChanged="tbUserName_TextChanged"/>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OneOnce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值