如何在 WPF 中制作带有 Button 的 TextBox?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1404057/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:58:33  来源:igfitidea点击:

How to make a TextBox with a Button inside in WPF?

wpfxamltextbox

提问by Max Galkin

I'd like to make a TextBoxwith a Buttoninside, something like a DatePicker, but not exactly. Or can it be a ComboBoxinside the TextBox, so you can switch the mode of the TextBox.

我想制作一个TextBox带有Button内部的东西,类似于 a DatePicker,但不完全是。或者可以是一个ComboBox里面的TextBox,这样就可以切换模式了TextBox

Can you help me?

你能帮助我吗?

采纳答案by Nir

If you want something like a combobox or a date time picker you should create a new control, inside this new control place a text box and a button side by side inside a frame that looks like the frame of a textbox - then restyle the textbox so it doesn't have a frame.

如果您想要组合框或日期时间选择器之类的东西,您应该创建一个新控件,在这个新控件中,将一个文本框和一个按钮并排放置在一个看起来像文本框框架的框架内 - 然后重新设置文本框的样式它没有框架。

putting a button inside a rich edit is great if you want to put a button inside a "document" but not a good substitute for a combobox.

如果您想将按钮放在“文档”中,但不能很好地替代组合框,则将按钮放在丰富的编辑中非常有用。

See the ComboBox control template MSDN

请参阅 ComboBox 控件模板MSDN

回答by Xiaoqing

You may find this link helps: http://msdn.microsoft.com/en-us/library/ms752068(VS.85).aspx.

您可能会发现此链接有帮助:http: //msdn.microsoft.com/en-us/library/ms752068(VS.85).aspx

"The ControlTemplate for a TextBox must contain exactly one element that is tagged as the content host element; this element will be used to render the contents of the TextBox. To tag an element as the content host, assign it the special name PART_ContentHost. The content host element must be either a ScrollViewer or an AdornerDecorator. The content host element may not host any child elements."

“TextBox 的 ControlTemplate 必须恰好包含一个标记为内容宿主元素的元素;该元素将用于呈现 TextBox 的内容。要将元素标记为内容宿主,请为其分配特殊名称 PART_ContentHost。内容宿主元素必须是 ScrollViewer 或 AdornerDecorator。内容宿主元素不能承载任何子元素。”

回答by Tim

I created a textbox control and added this It seems to work, but not the ideal situation cos it recreates another textbox.

我创建了一个文本框控件并添加了这个它似乎可以工作,但不是理想的情况,因为它重新创建了另一个文本框。

<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>

回答by Narendra

Just use Grid.Column same like below code

只需使用 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>

回答by MikeKulls

The correct method of doing this is to use a control template on the textbox. Something like below. I used this inside a class that inherits from textbox and called it ButtonBox. I then inherit others from this such as DateBox, DateTimeBox, SqlServerConnectBox etc.

这样做的正确方法是在文本框上使用控件模板。像下面这样的东西。我在继承自 textbox 的类中使用了它,并将其称为 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>

Edit: I've change the method I was using so that it inherits from control and not textbox. This works well because the control just consists of a border, a textbox and a button. I was getting focus issues with the above solution. This is new template, I have called my control a ButtonBox

编辑:我已经更改了我使用的方法,以便它继承自控件而不是文本框。这很有效,因为该控件仅由一个边框、一个文本框和一个按钮组成。我在上述解决方案中遇到了焦点问题。这是新模板,我称我的控件为 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>

回答by japf

You can also use a Label and change its template to include a Button in it. To have a good overview of differences between Label and TextBlock see this post.

您还可以使用 Label 并更改其模板以在其中包含一个 Button。要全面了解 Label 和 TextBlock 之间的差异,请参阅此帖子

回答by Firoz

You can use RichTextBox instead of textbox and it support flowdocument in which you can place the button in it.

您可以使用 RichTextBox 代替文本框,它支持流文档,您可以在其中放置按钮。

回答by Jan Rothkegel

You may use a grid to accomplish this task. The following is how I created a button which appears at the right bottom of a TextBox:

您可以使用网格来完成此任务。以下是我如何创建一个出现在 TextBox 右下角的按钮:

<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>