WPF为没有DataTemplate属性的控件创建DataTemplate

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF为没有DataTemplate属性的控件创建DataTemplate相关的知识,希望对你有一定的参考价值。

我正在为Slider创建一个自定义TickBar。这个CustomTickBar允许我在Slider上放置不同的标记。我将使用以下型号:

Interface IModel
{
   string Id;
}

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

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

我的想法是我为这个TickBar控件提供List<IModel>,并根据IModel的类型标记图标会改变;例如对于Model1,它将是一个三角形,对于Model2,它将是一个矩形。我知道使用DataTemplate可以实现这一点。但是WPF TickBar没有DataTemplate属性。现在有一种方法可以使用DataTemplate属性和子类化TickBar来实现这一点吗?

注意:我知道我可以使用OnRender()创建自定义刻度,但我正在尝试通过编写尽可能少的代码隐藏来检查是否有办法。

答案

TickBar没有默认样式,所以看起来像使用OnRender就是他们设计它的方式。

我想到的另一个解决方案是:

  1. 创建自定义控件,您拥有TickBar。也许从TickBar继承。
  2. 即使基于某些模型数据,您也可以为此自定义TickBar设置自己的样式。

使用themes/generic.xaml和此代码为您的控件应用自定义样式:

static void MyCustomTickBar() {
    DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomTickBar), new FrameworkPropertyMetadata(typeof(MyCustomTickBar)));
}
  1. 编辑Slider的模板并使用新的TickBar而不是内置的。

Here是Slider的默认模板。我使用了样式窥探器来提取它。对不起,我无法在答案中提供,这太长了。

另一答案

首先尝试为滑块创建样式。例如像这样的东西:

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

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

当滑块的datacontext对属性“IsDifferent”具有不同的值时,此新样式将更改外观。

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

当然,可以用您喜欢的不同形状替换绿色椭圆,并使用不同的属性。

对于模板问题,通常最好使用ControlTemplate或者ContentControl,其DataTemplate可以自由设置,并且可以作为您自己控件的父级。

另一答案

我最近尝试用自己的定制滑块覆盖onrender,这很棘手。我不会那样做。我建议您考虑添加另一个控件来保持标记并使其与滑块的高度或宽度相匹配。如果您的“滴答”处于固定状态,则可能只是包含路径的uniformgrid,您可以使用资源来使用DynamicResource几何来定义其数据。您可以通过合并不同的几何图形来切换几何图形,也可以将其数据化。

以上是关于WPF为没有DataTemplate属性的控件创建DataTemplate的主要内容,如果未能解决你的问题,请参考以下文章

WPF -- DataTemplate与ControlTemplate结合使用

WPF 后台获得 数据模板里的内容控件(DataTemplate)

WPF 详解模板

来自 DataTemplate 的 WPF 数据绑定 - 多对多关系

DataTemplate的用法

WPF 查找ListBox等DataTemplate下的子控件