如何将虚拟滑块创建为将按钮与文本框组合在一起的 WPF 自定义控件

本文关键字:组合 在一起 文本 自定义控件 WPF 按钮 虚拟 创建 | 更新日期: 2023-09-27 18:33:44

我想实现一个WPF CustomControl,那...

  1. 通常看起来像一个按钮,并将浮点值显示为字符串
  2. 拖动按钮时,浮点值像虚拟滑块一样纵
  3. 单击该按钮时,它将替换为一个文本框,该文本框预填充了当前值作为字符串。可以编辑此文本。在文本框外部单击或按回车键会将控件更改回"按钮",并使用编辑后的文本作为新值。

我们需要在高度简化的界面中进行此控件。虽然这个描述听起来有点奇怪,但它对我们来说效果非常好。但出于性能原因,我们现在必须将当前实现作为用户控件重构为自定义控件。

我运行了控件的滑块部分,并设法显示附加到内容依赖项属性的文本框。但是,遗憾的是,我无法从控件模板访问此文本框,它大致如下所示:

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

任何想法,如何将其作为自定义控件实现?

如何将虚拟滑块创建为将按钮与文本框组合在一起的 WPF 自定义控件

你的想法真的很不寻常。从可用性的角度来看,您不应该提供像按钮这样的知名控件的这种"令人惊讶"的行为。也许组合框将是更好的控制。它有一个文本部分,您可以在其中进行编辑,甚至还有一个下拉列表,您可以在其中提供预定义的值。使用不可见(背景 #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%;