3

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

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

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

我让控件的滑块部分运行并设法显示附加到 Content DependencyProperty 的 TextBox。然而,遗憾的是,我无法从 ControlTemplate 访问这个 TextBox,它看起来大致如下:

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

任何想法,如何将其实现为 CustomControl?

4

2 回答 2

0

你的想法真的很不寻常。从可用性的角度来看,您不应该提供像 Button 这样的知名控件的“令人惊讶”的行为。也许组合框会更好地控制这样做。它有一个可以编辑的文本部分,甚至还有一个下拉菜单,您可以在其中提供预定义的值。为拖动部分使用不可见的(背景#01ffffff)拇指)。

我不确定我是否正确理解您的问题。您不应该将您的依赖属性命名为“内容”。如果您从 Button 派生控件,则内容已全部定义为按钮内容。

于 2012-05-16T10:10:53.040 回答
0

经过一番摸索,我找到了以下解决方案:

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

从 UserControl 到 CustomControl 的重构加快了 50% 的实例化速度;

于 2012-05-26T22:26:17.750 回答