如何在WPF中制作一个内置按钮的文本框?
我想制作一个如何在WPF中制作一个内置按钮的文本框?,wpf,xaml,textbox,Wpf,Xaml,Textbox,我想制作一个文本框,里面有一个按钮,类似于日期选择器,但不完全是这样。或者它可以是文本框中的组合框,因此您可以切换文本框的模式 你能帮助我吗?你可以使用RichTextBox而不是textbox,它支持flowdocument,你可以在其中放置按钮。如果你想要一个组合框或日期时间选择器,你应该创建一个新控件,在这个新控件中,将一个文本框和一个按钮并排放置在一个看起来像文本框框架的框架内,然后重新设置文本框的样式,使其没有框架 如果你想把一个按钮放在一个“文档”中,但不是一个组合框的好替代品,那么
文本框
,里面有一个按钮
,类似于日期选择器
,但不完全是这样。或者它可以是文本框
中的组合框
,因此您可以切换文本框
的模式
你能帮助我吗?你可以使用RichTextBox而不是textbox,它支持flowdocument,你可以在其中放置按钮。如果你想要一个组合框或日期时间选择器,你应该创建一个新控件,在这个新控件中,将一个文本框和一个按钮并排放置在一个看起来像文本框框架的框架内,然后重新设置文本框的样式,使其没有框架 如果你想把一个按钮放在一个“文档”中,但不是一个组合框的好替代品,那么把一个按钮放在一个丰富的编辑中是很好的选择
请参见组合框控件模板您还可以使用标签并更改其模板以在其中包含按钮。要全面了解Label和TextBlock之间的差异,请参见。我创建了一个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>
您可能会发现此链接有帮助:
“文本框的ControlTemplate必须仅包含一个标记为内容宿主元素的元素;此元素将用于呈现文本框的内容。要将元素标记为内容宿主,请为其指定特殊名称PART\u ContentHost。内容宿主元素必须是ScrollViewer或AdornerDecorator。content host元素不能承载任何子元素。“正确的方法是在textbox上使用控件模板。如下所示。我在从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>
xmlns:mwt=“clr名称空间:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero“
...
假的
编辑:我已经更改了我使用的方法,使其继承自控件而不是文本框。这很好,因为控件只包含边框、文本框和按钮。我在上述解决方案中遇到焦点问题。这是一个新模板,我将我的控件称为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>
假的
您可以使用网格来完成此任务。以下是我如何创建一个显示在文本框右下角的按钮:
<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>
只需使用网格。列与下面的代码相同
<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>
简单解决方案
你可以把按钮放在文本框上,假装按钮在文本框中。别忘了在文本框上加上填充物,以免按钮后面出现文本 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>
<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>
带有网格的代码示例:
<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>
<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>
结果:
<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>
<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>
实际上,我最终选择了这种方式。我使用Border元素模拟文本框的外部边框,并使用Grid将真正的无边框文本框和按钮放入其中。我认为这不可行,文本(和其他属性)外部文本框和内部文本框的名称不同步。您应该使用名为ScrollViewer的
PART\u ContentHost
而不是内部文本框,就像原始模板一样。