WPF Создание DataTemplate для элемента управления, у которого нет свойства DataTemplate

Я создаю собственный TickBar для слайдера. Этот CustomTickBar позволяет мне ставить разные маркеры на слайдер. Я буду использовать следующую модель:

Interface IModel
{
   string Id;
}

Class Model1 : IModel
{
   string Id;
   string SomeProperty;
}

Class Model2 : IModel
{
   string Id;
   string SomeOtherProperty;
}

Идея состоит в том, что я предоставляю List<IModel> этому элементу управления TickBar, и в зависимости от типа IModel значок маркера будет изменяться; например для Model1 это будет треугольник, а для Model2 - прямоугольник. Я понимаю, что это возможно с помощью DataTemplate. Но WPF TickBar не имеет свойства DataTemplate. Есть ли способ сделать это с помощью свойства DataTemplate и создания подкласса TickBar?

Примечание. Я понимаю, что могу создать собственный тик с помощью OnRender (), но я пытаюсь проверить, есть ли способ сделать это, написав как можно меньше кода программной части.

CustomTickBar может иметь настраиваемые маркеры, которые, в свою очередь, могут иметь свойство DataTemplate.

ASh 11.03.2018 08:16

@ASh не могли бы вы привести пример? Не могу понять это.

SZT 11.03.2018 09:27

@ASh Если бы вы читали исходный код TickBar, вы бы знали, что визуальный элемент TickBar был нарисован непосредственно в методе OnRender, потому что он зависит от других свойств динамически. Таким образом, DataTemplate решит вашу проблему, но замена OnRender поможет.

Alex.Wei 20.03.2018 11:02

А как насчет положения клещей? вы хотите определить пользовательские позиции или как-то использовать частоту TickBar?

SamTh3D3v 22.03.2018 15:49

@Usama Я бы использовал нестандартные позиции. Таким образом, они могут появиться в любом месте ползунка.

SZT 23.03.2018 07:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
434
3

Ответы 3

Недавно я сам пробовал переопределить onrender для настраиваемого слайдера, и это сложно. Я бы не пошел по этому пути. Я предлагаю вам подумать о добавлении еще одного элемента управления, который будет удерживать маркеры и соответствовать высоте или ширине вашего слайдера. Если ваши «галочки» зафиксированы, то это может быть просто равномерная сетка, содержащая пути, и вы используете ресурс для определения их данных с помощью геометрии DynamicResource. Вы можете переключать геометрию, объединяя разные или наклеивая на нее данные.

TickBar не имеет стиля по умолчанию, поэтому похоже, что использование OnRender - это то, как они его разработали.

Другое решение, о котором я думаю, было бы:

  1. Создайте собственный элемент управления, у вас есть TickBar. Может быть, унаследовать от TickBar.
  2. Вы можете установить свой собственный стиль для этого пользовательского TickBar, даже на основе некоторых данных вашей модели.

Используйте themes/generic.xaml и этот код, чтобы применить собственный стиль для вашего элемента управления:

static void MyCustomTickBar() {
    DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomTickBar), new FrameworkPropertyMetadata(typeof(MyCustomTickBar)));
}
  1. Отредактируйте шаблон Slider и используйте новый TickBar вместо встроенного.

Здесь - шаблон по умолчанию для слайдера. Я использовал style snooper, чтобы извлечь его. Извините, я не смог указать это в своем ответе, это слишком долго.

Попробуйте сначала создать стиль для слайдера. например Что-то вроде этого:

<Window.Resources>
    <SolidColorBrush x:Key = "HorizontalSliderTrackNormalBackground" Color = "#FFE7EAEA"/>
    <LinearGradientBrush x:Key = "HorizontalSliderTrackNormalBorder" EndPoint = "0,1" StartPoint = "0,0">
        <GradientStop Color = "#FFAEB1AF" Offset = "0.1"/>
        <GradientStop Color = "#FFAEB1AF" Offset = ".9"/>
    </LinearGradientBrush>
    <Style x:Key = "SliderRepeatButtonStyle" TargetType = "{x:Type RepeatButton}">
        <Setter Property = "OverridesDefaultStyle" Value = "true"/>
        <Setter Property = "IsTabStop" Value = "false"/>
        <Setter Property = "Focusable" Value = "false"/>
        <Setter Property = "Template">
            <Setter.Value>
                <ControlTemplate TargetType = "{x:Type RepeatButton}">
                    <Rectangle Fill = "Transparent"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key = "CustomThumbForSlider" TargetType = "{x:Type Thumb}">
        <Setter Property = "OverridesDefaultStyle" Value = "True"/>
        <Setter Property = "Template">
            <Setter.Value>
                <ControlTemplate TargetType = "{x:Type Thumb}">
                    <Ellipse Fill = "#009EFF" Stroke = "#009EFF" Height = "14" Width = "14"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key = "MyCustomStyleForSlider" TargetType = "{x:Type Slider}">
        <Setter Property = "Template">
            <Setter.Value>
                <ControlTemplate TargetType = "{x:Type Slider}">
                    <Border Background = "{TemplateBinding Background}" BorderBrush = "{TemplateBinding BorderBrush}" BorderThickness = "{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height = "auto"/>
                                <RowDefinition Height = "Auto" MinHeight = "{TemplateBinding MinHeight}"/>
                                <RowDefinition Height = "Auto"/>
                            </Grid.RowDefinitions>
                            <TickBar x:Name = "TopTick" Visibility = "Collapsed" Fill = "{TemplateBinding Foreground}" Placement = "Top" Height = "10" Grid.Row = "2"/>
                            <TickBar x:Name = "BottomTick" Visibility = "Collapsed" Fill = "{TemplateBinding Foreground}" Placement = "Bottom" Height = "10" Grid.Row = "2"/>
                            <Border x:Name = "TrackBackground" 
                                    Background = "{StaticResource HorizontalSliderTrackNormalBackground}"
                                    BorderBrush = "{StaticResource HorizontalSliderTrackNormalBorder}"                                        
                                    BorderThickness = "2" CornerRadius = "1"
                                    Margin = "5,0" VerticalAlignment = "Center" Height = "10.0" Grid.Row = "1" >
                                <Canvas Margin = "-6,-2">
                                    <Rectangle Visibility = "Hidden" x:Name = "PART_SelectionRange" Height = "6.0"
                                               Fill = "{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"
                                               Stroke = "{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}"
                                               StrokeThickness = "2.0"/>
                                </Canvas>
                            </Border>
                            <Track x:Name = "PART_Track" Grid.Row = "1"  >
                                <Track.DecreaseRepeatButton>
                                    <RepeatButton  Style = "{StaticResource  SliderRepeatButtonStyle}" Command = "{x:Static Slider.DecreaseLarge}"/>
                                </Track.DecreaseRepeatButton>
                                <Track.IncreaseRepeatButton>
                                    <RepeatButton Style = "{StaticResource SliderRepeatButtonStyle}" Command = "{x:Static Slider.IncreaseLarge}"/>
                                </Track.IncreaseRepeatButton>
                                <Track.Thumb>
                                    <Thumb x:Name = "Thumb" Style = "{StaticResource CustomThumbForSlider}" Background = "Black"/>
                                </Track.Thumb>
                            </Track>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

Затем вы можете определить слайдер, который использует стиль:

<Slider Name = "CustomSlider" Style = "{StaticResource MyCustomStyleForSlider}"/>

Чтобы изменить стиль в зависимости от некоторых свойств, вы можете добавить триггер данных. просто замените существующий стиль новым:

<Style x:Key = "CustomThumbForSlider" TargetType = "{x:Type Thumb}">
    <Setter Property = "OverridesDefaultStyle" Value = "True"/>
    <Setter Property = "Template">
        <Setter.Value>
            <ControlTemplate TargetType = "{x:Type Thumb}">
                <Ellipse Fill = "#009EFF" Stroke = "#009EFF" Height = "14" Width = "14"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <DataTrigger Binding = "{Binding Path=IsDifferent}" Value = "True">
            <Setter Property = "Template">
                <Setter.Value>
                    <ControlTemplate TargetType = "{x:Type Thumb}">
                        <Ellipse Fill = "#009055" Stroke = "#009055" Height = "14" Width = "14"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

Этот новый стиль изменит внешний вид, когда контекст данных слайдера имеет другое значение для свойства IsDifferent.

<Slider Name = "CustomSlider" Style = "{StaticResource MyCustomStyleForSlider}" DataContext = "{Binding Path=MyContext}"/>

Конечно, можно было бы заменить зеленый эллипс другой формой по своему вкусу, а также использовать другое свойство.

Для задачи создания шаблонов обычно лучше использовать ControlTemplate или, альтернативно, ContentControl, DataTemplate которого может быть установлен свободно и который будет выступать в качестве родительского элемента для ваших собственных элементов управления.

Другие вопросы по теме