Хобрук: Ваш путь к мастерству в программировании

Как создать виртуальный слайдер как WPF-CustomControl, который сочетает в себе кнопку с текстовым полем

Я хочу реализовать WPF CustomControl, который...

  1. Обычно выглядит как кнопка и отображает значение с плавающей запятой в виде строки
  2. При перетаскивании кнопки значением с плавающей запятой управляют как виртуальным ползунком.
  3. При нажатии кнопки она заменяется текстовым полем, предварительно заполненным текущим значением в виде строки. Этот текст можно редактировать. Если щелкнуть за пределами TextBox или нажать клавишу возврата, элемент управления снова изменится на Button, а отредактированный текст будет использоваться в качестве нового значения.

Нам нужен этот элемент управления в высоко оптимизированном интерфейсе. Хотя описание звучит немного странно, для нас оно работает на удивление хорошо. Но по соображениям производительности нам теперь нужно реорганизовать текущую реализацию как UserControl в CustomControl.

Я запустил ползунок элемента управления и смог показать TextBox, прикрепленный к Content DependencyProperty. Однако, к сожалению, мне не удается получить доступ к этому TextBox из ControlTemplate, который выглядит примерно так:

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


Ответы:


1

ваша идея действительно необычна. С точки зрения удобства использования вы не должны предлагать такое «удивительное» поведение хорошо известных элементов управления, таких как Button. Возможно, поле со списком было бы лучшим средством для этого. В нем есть текстовая часть, которую вы можете редактировать, и даже раскрывающийся список, в котором вы можете предлагать предопределенные значения. используйте невидимый (фон #01ffffff) большой палец для перетаскивания).

Я не уверен, что правильно понимаю вашу проблему. Вы не должны называть свойство зависимостей "Content". Если вы получили свой элемент управления от кнопки, содержимое уже определено как содержимое кнопки.

16.05.2012
  • Он имеет в виду создание функциональности, похожей на определенные поля ввода в Blend. Вы можете перетащить мышь вверх или вниз, если вам нужны большие изменения определенного значения, а затем переключиться на клавиатуру для точного ввода. 25.05.2012
  • Спасибо за ваш отзыв. Я знаю шансы решения, но, как я уже сказал, оно проверено пользователями и работает очень хорошо :-) 27.05.2012

  • 2

    Немного повозившись, я нашел следующее решение:

    Шаблон в 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%;

    26.05.2012
    Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..