如何在WPF中创建一个包含按钮的文本框?

15
我想创建一个带有按钮的文本框,类似于日期选择器,但不完全相同。或者可以在文本框内部放置一个组合框,以便切换文本框的模式。
你能帮助我吗?
9个回答

12
如果您想要类似于组合框或日期时间选择器的东西,您应该创建一个新控件,在这个新控件内放置一个文本框和一个按钮,将它们并排放在一个看起来像文本框的框架内 - 然后重新设计文本框,使其没有框架。
如果您想在“文档”中放置一个按钮,将按钮放在富文本中是很好的,但不能替代组合框。
请参见ComboBox控件模板MSDN

最终我选择了这种方式。我使用了Border元素来模拟文本框的外边框,并在其中使用Grid将真正没有边框的文本框和按钮放置在内部。 - Massimiliano

6

简单解决方法


你可以通过将按钮放在文本框上方来假装按钮在文本框内。别忘了在文本框上加填充以避免文字被按钮遮挡。

使用 StackPanel 的代码示例:

<StackPanel Orientation="Horizontal">
    <TextBox Width="200" Padding="0,0,30,0" Height="30" FontSize="16"/>
    <Button Width="20" Height="20" Margin="-30,0,0,0"/>
</StackPanel>

使用Grid的代码示例:

<Grid>
    <TextBox Width="200" Padding="0,0,30,0" Height="30" FontSize="16"/>
    <Button Width="20" Height="20" HorizontalAlignment="Right" Margin="0,0,5,0"/>
</Grid>

结果:

这里输入图片描述


6

我创建了一个文本框控件并添加了它。

它似乎能够工作,但不是理想的情况,因为它会重新创建另一个文本框。

<TextBox.Template>
 <ControlTemplate>
        <Grid>
            <Grid.ColumnDefinitions></Grid.ColumnDefinitions>
            <TextBox Grid.Column="0"></TextBox>
            <Button HorizontalAlignment="Right" Width="25" Grid.Column="1">
            </Button>
        </Grid>         
    </ControlTemplate>
</TextBox.Template>

我认为这不会起作用,外部和内部文本框的文本(以及其他属性)没有同步。你应该使用一个名为ScrollViewer的PART_ContentHost代替内部文本框,就像原始模板一样。 - Zarat

5
你可以参考这个链接:http://msdn.microsoft.com/en-us/library/ms752068(VS.85).aspx
文本框的控件模板(ControlTemplate) 必须包含且只能包含一个被标记为内容主机元素的元素;该元素将用于呈现文本框的内容。要将一个元素标记为内容主机,需要给它指定一个特殊的名称PART_ContentHost。内容主机元素必须是ScrollViewer或AdornerDecorator类型之一。内容主机元素不能承载任何子元素。

0
正确的方法是在文本框上使用控件模板。类似下面这样的东西。我在继承自文本框的类中使用了它,并称之为ButtonBox。然后我从这个类继承其他类,比如DateBox、DateTimeBox、SqlServerConnectBox等等。
    xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"

<TextBox.Template>
    <ControlTemplate TargetType="{x:Type TextBoxBase}">
        <mwt:ListBoxChrome 
            Background="{TemplateBinding Panel.Background}"
            BorderBrush="{TemplateBinding Border.BorderBrush}"
            BorderThickness="{TemplateBinding Border.BorderThickness}"
            RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}"
            RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}"
            Name="Bd"
            SnapsToDevicePixels="True">

            <DockPanel>
                <Button DockPanel.Dock="Right" Name="myButton" Padding="3,0" Click="myButton_Click">...</Button>
                <ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"></ScrollViewer>
            </DockPanel>
        </mwt:ListBoxChrome>
        <ControlTemplate.Triggers>
            <Trigger Property="UIElement.IsEnabled">
                <Setter Property="Panel.Background" TargetName="Bd">
                    <Setter.Value>
                        <DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
                    </Setter.Value>
                </Setter>
                <Setter Property="TextElement.Foreground">
                    <Setter.Value>
                        <DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
                    </Setter.Value>
                </Setter>
                <Trigger.Value>
                    <s:Boolean>False</s:Boolean>
                </Trigger.Value>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
</TextBox.Template>

编辑:我已经更改了我使用的方法,使其继承自控件而不是文本框。这很有效,因为该控件只包含边框、文本框和按钮。我在上面的解决方案中遇到了焦点问题。这是新模板,我将我的控件称为ButtonBox。

<Style TargetType="{x:Type local:ButtonBox}">
    <Setter Property="Border.BorderThickness" Value="1"></Setter>
    <Setter Property="Border.BorderBrush">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,20" MappingMode="Absolute">
                <LinearGradientBrush.GradientStops>
                    <GradientStop Color="#FFABADB3" Offset="0.05" />
                    <GradientStop Color="#FFE2E3EA" Offset="0.07" />
                    <GradientStop Color="#FFE3E9EF" Offset="1" />
                </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ButtonBox}">
                <mwt:ListBoxChrome 
                    Background="{TemplateBinding Panel.Background}"
                    BorderThickness="{TemplateBinding Border.BorderThickness}"
                    BorderBrush="{TemplateBinding Border.BorderBrush}"
                    RenderMouseOver="{TemplateBinding UIElement.IsMouseOver}"
                    RenderFocused="{TemplateBinding UIElement.IsKeyboardFocusWithin}"
                    Name="Bd"
                    SnapsToDevicePixels="True">
                    <DockPanel>
                        <Button
                            DockPanel.Dock="Right"
                            Name="PART_Button"
                            Height="0"
                            Style="{x:Null}"
                            Margin="0"
                            Padding="3,0"
                            Content="{TemplateBinding local:ButtonBox.ButtonContent}"
                            IsTabStop="False">                                
                        </Button>
                        <TextBox
                            BorderBrush="{x:Null}"
                            BorderThickness="0"
                            Margin="0"
                            Name="PART_ContentHost"
                            IsReadOnly="{TemplateBinding TextBox.IsReadOnly}"
                            Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, Path=Text}">                                
                        </TextBox>
                        <!-- ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" Margin="1"></ScrollViewer -->
                    </DockPanel>
                </mwt:ListBoxChrome>
                <ControlTemplate.Triggers>
                    <Trigger Property="UIElement.IsEnabled">
                        <Setter Property="Panel.Background" TargetName="Bd">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="TextElement.Foreground">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Trigger.Value>
                            <s:Boolean>False</s:Boolean>
                        </Trigger.Value>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="IsTabStop" Value="False"></Setter>
</Style>

0
你可以使用RichTextBox代替textbox,它支持flowdocument,在其中可以放置按钮。

0

您还可以使用标签(Label)并更改其模板(template)以在其中包含一个按钮(Button)。要全面了解标签(Label)和文本块(TextBlock)之间的区别,请参见此帖子


0

只需像下面的代码一样使用Grid.Column

<TextBox x:Name="txtUrl" Grid.Column="1" Margin="2,2,0,2" VerticalAlignment="Center" Padding="2" PreviewKeyDown="txtUrl_PreviewKeyDown" GotFocus="txtUrl_GotFocus" PreviewMouseDown="txtUrl_PreviewMouseDown"> 

</TextBox>
<eo:BareButton x:Name="btnAddFavorite" Grid.Column=" 1"   HorizontalAlignment="Right" Style="{StaticResource WindowButtonStyle }" Margin="2" >
    <eo:BareButton.Template>
        <ControlTemplate TargetType="{x:Type eo:BareButton}">
            <Border x:Name="PART_Border" Width="22" Height="22" Background="Transparent" VerticalAlignment="Center" Margin="2,0,0,0" CornerRadius="2">
                <Path 
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
                                                            Fill="Yellow" 

            Data="M 2,9 L 8,8 10,2 13,8 19,9 15,13 16,19 10,15 5,19 6,13 2,9"
        SnapsToDevicePixels="false"
            Stroke="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type eo:BareButton}, Mode=FindAncestor}}"
            StrokeThickness="1" />
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter TargetName="PART_Border" Property="BorderBrush" Value="#666"/>
                    <Setter TargetName="PART_Border" Property="BorderThickness" Value="1"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </eo:BareButton.Template>

</eo:BareButton>

-1
你可以使用一个网格来完成这个任务。以下是我创建一个按钮出现在文本框右下角的方法:
<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <TextBox VerticalAlignment="Stretch"  HorizontalAlignment="Stretch" Grid.Row="0" />

        <Button Content="Copy" Width="40" Height="40" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="10" Grid.Row="0" />

</Grid>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接