How to create a virtual slider like WPF-CustomControl, which combines Button with TextBox

I want to implement a WPC CustomControl that ...

  • Usually looks like a button and displays the float value as a string
  • When dragging a button, the float value is treated as a virtual slider
  • When a button is pressed, it is replaced by a text field filled with the current value as a string. This text can be edited. Clicking outside the TextBox or clicking on the return changes the control to the button and uses the edited text as the new value.

We need this control in a highly optimized interface. Although the description sounds a little strange, it works great for us. But for performance reasons, we now have to reorganize the current implementation as a UserControl into a CustomControl.

I got the control slider part and was able to show a TextBox attached to Content DependencyProperty. Unfortunately, however, I cannot access this TextBox from a ControlTemplate, which looks something like this:

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

Any idea how this can be implemented as a CustomControl?

+3
source share
2 answers

With a little work, I found the following solution:

The template in Generic.xaml looks like this:

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

The initialization function looks something like this: the important part is to overwrite OnApplyTemplate and use 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;
}

Internal member variables are later used as ...

private void LostFocusHandler(object sender, RoutedEventArgs e) {
    if (!UpdateValueFromTextEdit())
        _textBox.Text = Value.ToString();

    _textBox.Visibility = Visibility.Collapsed;
    e.Handled= true;
}

Refactoring from UserControl to CustomControl speeds up installation by 50%;

0
source

. "" , Button. , combobox . , , , . ( # 01ffffff) ).

, . "". , .

0

All Articles