WPF customized TextBox

匆匆过客 提交于 2019-12-13 19:09:10

问题


I have a customized TextBox named "txtAddress" which contains Image and TextBox.
I need to be able to access its contents : txtAddress.Text txtAddress.Image
I've Bound the inner textBox.text with the Template.Text and inner rect.Fill with Template.Background (I'm using rectangular now, i will change it to image)

when I run the program and edit the textBox everything looks like its working and the text is changing, but when i use it from the code txtAddress.Text is still "my computer" which is the initial value of the TextBox. I know that because i didn't put <ContentPresenter> somewhere in the style but where should i put the controls(image,textbox), like in listView there is <DataTemplate> where we add the controls

TxtAddress Style:

<Style x:Key="TextBoxAddressStyle" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
        <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="AllowDrop" Value="true"/>
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
        <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Grid HorizontalAlignment="Stretch" Height="Auto" VerticalAlignment="Stretch" Width="Auto">
                        <Rectangle Height="Auto" Stroke="{TemplateBinding Foreground}" VerticalAlignment="Stretch" RadiusY="11" RadiusX="11" Margin="0" Fill="{TemplateBinding OpacityMask}"/>
                        <!--<ContentPresenter Height="Auto" Margin="31,2,7.458,2"/>-->
                        <TextBox x:Name="TxtAddress" Height="Auto" Margin="31,2,7.458,2" VerticalAlignment="Stretch" MaxLines="1" Text="{TemplateBinding Text}" AcceptsTab="True" Style="{DynamicResource TextBoxStyle2}" SelectionBrush="#C859003D" FontSize="{TemplateBinding FontSize}" AcceptsReturn="False"/>
                        <Rectangle Fill="#5AFFFFFF" HorizontalAlignment="Stretch" Height="6.375" Margin="6,2.25,6,0" RadiusY="6" RadiusX="6" Stroke="{x:Null}" VerticalAlignment="Top" Width="Auto" d:IsLocked="True"/>
                        <Rectangle x:Name="ImgAddress" Fill="{TemplateBinding Background}" HorizontalAlignment="Left" Height="24" Margin="7,1,0,0" RadiusY="0" RadiusX="0" VerticalAlignment="Top" Width="24" StrokeThickness="0">
                            <Rectangle.Stroke>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="Black" Offset="1"/>
                                    <GradientStop Color="White"/>
                                </LinearGradientBrush>
                            </Rectangle.Stroke>
                        </Rectangle>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
                    <Condition Property="IsSelectionActive" Value="false"/>
                </MultiTrigger.Conditions>
                <Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
            </MultiTrigger>
        </Style.Triggers>
    </Style>

Inner TextBox Style:

<Style x:Key="TextBoxStyle2" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
        <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="AllowDrop" Value="true"/>
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
        <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" FontSize="13.333" PanningMode="HorizontalOnly"/>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
                    <Condition Property="IsSelectionActive" Value="false"/>
                </MultiTrigger.Conditions>
                <Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
            </MultiTrigger>
        </Style.Triggers>
    </Style>

TxtAddress :

 <TextBox x:Name="txtAddress" Margin="34,5,32,0" TextWrapping="Wrap" Text="My Computer" Style="{DynamicResource TextBoxAddressStyle}" Height="25" VerticalAlignment="Top" FontWeight="Bold" MinHeight="25" MaxHeight="25">
            <TextBox.Background>
                <ImageBrush ImageSource="BtnImg/computer.png" Stretch="None"/>
            </TextBox.Background>
            <TextBox.Foreground>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF779198" Offset="0.1"/>
                    <GradientStop Color="#FF789399" Offset="0.93"/>
                    <GradientStop Color="#FFBFD3D7" Offset="0.513"/>
                    <GradientStop Color="#FF343E41" Offset="1"/>
                    <GradientStop Color="#FF5C6E73"/>
                </LinearGradientBrush>
            </TextBox.Foreground>
            <TextBox.OpacityMask>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF94B5BD" Offset="0.1"/>
                    <GradientStop Color="#FF94B5BD" Offset="0.93"/>
                    <GradientStop Color="#FFE7FBFF" Offset="0.513"/>
                    <GradientStop Color="#FF7B9399" Offset="1"/>
                    <GradientStop Color="#FF7B9399"/>
                </LinearGradientBrush>
            </TextBox.OpacityMask>
        </TextBox>

thanks in advance.


回答1:


You're placing a TextBox inside the Template for another TextBox.

The visual tree will look like this:

TextBox
   Grid
      Rectangle 
      TextBox
      Rectangle 
      Rectangle

Which is not ideal in the first place, but if you want to keep things like that, just make sure you bind the inner TextBox's Text property to the outer one, via Two Way, UpdateSourceTrigger=PropertyChanged Data Binding like so:

<TextBox x:Name="TxtAddress" Text="{Binding Text, 
                                            Mode=TwoWay, 
                                            UpdateSourceTrigger=PropertyChanged,  
                                            RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}" ... />

In addition to all this, I already mentioned several times that you're NOT supposed to be manipulating UI elements in procedural code in WPF.

Instead, create a proper ViewModel to store your data:

public class MyViewModel
{
    public string Text {get;set;}
}

then use DataBinding to bind your TextBox to that data:

<TextBox Text="{Binding Text}"/>

And whenever you need to retrieve the value, retrieve the value from the VM, NOT the UI.



来源:https://stackoverflow.com/questions/20614984/wpf-customized-textbox

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!