如何将虚拟滑块创建为将按钮与文本框组合在一起的 WPF 自定义控件
本文关键字:组合 在一起 文本 自定义控件 WPF 按钮 虚拟 创建 | 更新日期: 2023-09-27 18:33:44
我想实现一个WPF CustomControl,那...
- 通常看起来像一个按钮,并将浮点值显示为字符串
- 拖动按钮时,浮点值像虚拟滑块一样纵
- 单击该按钮时,它将替换为一个文本框,该文本框预填充了当前值作为字符串。可以编辑此文本。在文本框外部单击或按回车键会将控件更改回"按钮",并使用编辑后的文本作为新值。
我们需要在高度简化的界面中进行此控件。虽然这个描述听起来有点奇怪,但它对我们来说效果非常好。但出于性能原因,我们现在必须将当前实现作为用户控件重构为自定义控件。
我运行了控件的滑块部分,并设法显示附加到内容依赖项属性的文本框。但是,遗憾的是,我无法从控件模板访问此文本框,它大致如下所示:
<Style TargetType="{x:Type local:FloatEditButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FloatEditButton}">
<Grid Margin="0">
<Viewbox VerticalAlignment="Center" HorizontalAlignment="{Binding RelativeSource={RelativeSource TemplatedParent},Path=HorizontalContentAlignment}" Margin="0">
<ContentPresenter Name="content" Margin="2" VerticalAlignment="Center" />
</Viewbox>
<TextBox x:Name="XTextBox" Visibility="Collapsed" Text="{Binding Content}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="EditingAsTextBox" Value="True">
<Setter TargetName="XTextBox" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
任何想法,如何将其作为自定义控件实现?
你的想法真的很不寻常。从可用性的角度来看,您不应该提供像按钮这样的知名控件的这种"令人惊讶"的行为。也许组合框将是更好的控制。它有一个文本部分,您可以在其中进行编辑,甚至还有一个下拉列表,您可以在其中提供预定义的值。使用不可见(背景 #01ffffff(拇指作为拖动部分(。
我不是舒尔,我理解你的问题。不应将依赖项属性命名为"内容"。如果从按钮派生控件,则内容已全部定义为按钮内容。
摸索了一会儿后,我找到了以下解决方案:
Generic.xaml 中的模板如下所示...
<Style TargetType="{x:Type local:FloatEditButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FloatEditButton}">
<Grid Margin="0">
<TextBlock x:Name="PART_TextBlock" Grid.Row="1"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="0"
FontSize="{TemplateBinding FontSize}"
></TextBlock>
<Canvas x:Name="SliderCanvas" Grid.Row="1" IsHitTestVisible="False" Margin="0,3,0,2">
<Rectangle x:Name="PART_SliderDefaultRectangle" Width="1" Height="3" Canvas.Bottom="0" Fill="Black"/>
<Rectangle x:Name="PART_SliderMarkerRectangle" Width="1" Canvas.Top="0" Canvas.Left="20" Fill="#30ffffff" Height="{Binding ElementName=SliderCanvas, Path=ActualHeight}" />
<Rectangle x:Name="PART_SliderFillRectangle" Width="10" Fill="#10ffffff" Height="{Binding ElementName=SliderCanvas, Path=ActualHeight}" />
</Canvas>
<TextBox x:Name="PART_TextBox"
Visibility="Collapsed"
FontSize="{TemplateBinding FontSize}"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
初始值设定项函数大致如下所示: 重要的部分是覆盖 OnApplyTemplate 并使用 GetTemplateChild((。
/**
* Since we're using a CostumControl, we need to get the relevant UI children for the current instance
* for changing their properties later and assigning eventhandlers.
*/
public override void OnApplyTemplate() {
base.OnApplyTemplate();
_textBox = GetTemplateChild("PART_TextBox") as TextBox; // NOTE: FindName("PART_TextBox"); does NOT work here
MouseLeftButtonDown+= MouseLeftButtonDownHandler;
MouseLeftButtonUp+= MouseLeftButtonUpHandler;
MouseMove+= MouseMoveHandler;
MouseWheel+= MouseWheelHandler;
LayoutUpdated+=LayoutUpdatedHandler;
if (_textBox !=null) {
_textBox.TextChanged += TextChangedHandler;
_textBox.KeyUp += KeyUpHandler;
_textBox.LostFocus += LostFocusHandler;
}
_sliderFillRectangle = GetTemplateChild("PART_SliderFillRectangle") as Rectangle;
_sliderDefaultRectangle = GetTemplateChild("PART_SliderDefaultRectangle") as Rectangle;
_sliderMarkerRectangle = GetTemplateChild("PART_SliderMarkerRectangle") as Rectangle;
_textBlock = GetTemplateChild("PART_TextBlock") as TextBlock;
}
内部成员变量稍后使用,例如...
private void LostFocusHandler(object sender, RoutedEventArgs e) {
if (!UpdateValueFromTextEdit())
_textBox.Text = Value.ToString();
_textBox.Visibility = Visibility.Collapsed;
e.Handled= true;
}
从用户控件到自定义控件的重构将实例化速度提高了 50%;