【问题标题】:WPF - Create reusable style with variables/parametersWPF - 使用变量/参数创建可重用样式
【发布时间】:2013-10-16 08:23:15
【问题描述】:

我有一个包含多个 TabItems 的 WPF 应用程序。每个 TabItem 都各不相同,有一个文本和一个图标。

TabItem 的样式是这样定义的:

<TabItem.Style>
                    <Style TargetType="TabItem">
                        <Setter Property="Header">
                            <Setter.Value>
                                <StackPanel Orientation="Horizontal">
                                    <Image Margin="10,0,0,0" Height="40" Width="40" Source="Images/IconLeafGrey.png"/>
                                    <TextBlock Text="This is the heading" VerticalAlignment="Center" Style="{StaticResource Heading2}" Margin="10,0,0,0"/>
                                </StackPanel>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type TabItem}">
                                    <Grid>
                                        <Border Name="Border" BorderBrush="Black" BorderThickness="1,1,1,1" CornerRadius="6,6,0,0" >
                                            <Border.Background>
                                                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                                    <GradientStop Color="#f5f7f8" Offset="0.0" />
                                                    <GradientStop Color="#c5d0dd" Offset="1.0" />
                                                </LinearGradientBrush>
                                            </Border.Background>
                                            <ContentPresenter Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Left" ContentSource="Header" Margin="5,2,0,2"/>
                                        </Border>
                                    </Grid>
                                    <ControlTemplate.Triggers>
                                        <Trigger Property="IsSelected" Value="True">
                                            <Setter Property="Background" TargetName="Border">
                                                <Setter.Value>
                                                    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                                        <LinearGradientBrush.GradientStops>
                                                            <GradientStop Color="#ebedee" Offset="0.0" />
                                                            <GradientStop Color="#88a2bd" Offset="1.0" />
                                                        </LinearGradientBrush.GradientStops>
                                                    </LinearGradientBrush>
                                                </Setter.Value>
                                            </Setter>
                                        </Trigger>
                                    </ControlTemplate.Triggers>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                        <Style.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Header">
                                    <Setter.Value>
                                        <StackPanel Orientation="Horizontal">
                                            <Image Margin="10,0,0,0" Height="40" Width="40" Source="Images/IconLeaf.png"/>
                                            <TextBlock Text="This is the heading" VerticalAlignment="Center" Style="{StaticResource Heading2}" Margin="10,0,0,0"/>
                                        </StackPanel>
                                    </Setter.Value>
                                </Setter>

                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TabItem.Style>

因此,我不想为每个 TabItem 编写此 XAML 标记,而是想在我的 ResourceDictionary 中定义一次此样式,但将 Icon 和 Text 属性作为可选参数。所以我之后可以像这样定义一个 TabItem:

<TabItem Width="250" Height="60" Style="{StaticResource CustomTabItem}" >

我已经读到,样式不能直接接受这样的参数,但它应该可以通过某种绑定来实现。我还没有找到具体的方法,所以我真的希望你能提供帮助。

亲切的问候。

【问题讨论】:

  • 您可以创建样式Based On 仅覆盖图标和文本属性的主要样式。

标签: wpf styles


【解决方案1】:

一种方法是,如果您有固定数量的 TabItems 并且您不想在 TabControl 上生成 TabItemsItemsSource Binding。然后在您的TabItem.Style 中,您可以使用Resource 键来获取文本和来源,例如:

    <StackPanel Orientation="Horizontal">
         <Image Margin="10,0,0,0" Height="40" Width="40" Source="{DynamicResource Image1}"/>
         <TextBlock Text="{DynamicResource Header}" VerticalAlignment="Center" Style="{StaticResource Heading2}" Margin="10,0,0,0"/>
     </StackPanel>

您可以为您的 TabItems 定义这些资源:

     <TabItem Width="250" Height="60" Style="{StaticResource CustomTabItem}">
         <TabItem.Resources>
               <System:String x:Key="Header">TabItem1</System:String>
               <System:String x:Key="Image1">image/1.png</System:String>
               <System:String x:Key="Image2">image/2.png</System:String>
          </TabItem.Resources>
      </TabItem>
       <TabItem Width="250" Height="60" Style="{StaticResource CustomTabItem}">
         <TabItem.Resources>
               <System:String x:Key="Header">TabItem2</System:String>
               <System:String x:Key="Image1">image/3.png</System:String>
               <System:String x:Key="Image2">image/4.png</System:String>
          </TabItem.Resources>
      </TabItem>

您还需要更新您的Style 以设置HeaderTemplate 而不是Header

     <Style x:Key="CustomTabItem" TargetType="TabItem">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image x:Name="HeaderImage" Margin="10,0,0,0" Height="40" Width="40" Source="Images/IconLeafGrey.png"/>
                        <TextBlock Text="{DynamicResource Header}" VerticalAlignment="Center"  Margin="10,0,0,0"/>
                    </StackPanel>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}" Value="true">
                            <Setter TargetName="HeaderImage" Property="Source" Value="Images/IconLeaf.png"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>

            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabItem}">
                    <Grid>
                        <Border Name="Border" BorderBrush="Black" BorderThickness="1,1,1,1" CornerRadius="6,6,0,0" >
                            <Border.Background>
                                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                    <GradientStop Color="#f5f7f8" Offset="0.0" />
                                    <GradientStop Color="#c5d0dd" Offset="1.0" />
                                </LinearGradientBrush>
                            </Border.Background>
                            <ContentPresenter Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Left" ContentSource="Header" Margin="5,2,0,2"/>
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Background" TargetName="Border">
                                <Setter.Value>
                                    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                        <LinearGradientBrush.GradientStops>
                                            <GradientStop Color="#ebedee" Offset="0.0" />
                                            <GradientStop Color="#88a2bd" Offset="1.0" />
                                        </LinearGradientBrush.GradientStops>
                                    </LinearGradientBrush>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

【讨论】:

  • 非常感谢,它似乎正在工作......几乎!问题是,当我在两个或多个 TabItem 上设置样式时,Visual Studio 会警告我“指定的元素已经是另一个元素的逻辑子元素。首先断开它”。如果我运行应用程序,它会因“设置属性 'System.Windows.FrameworkElement.Style' 引发异常而失败。”我已经摆弄了它,如果我从样式中删除整个 Header 部分,错误就会消失......有什么想法吗?
  • 您能分享一下您是如何定义资源的吗?
  • 我现在更新了我如何定义资源的问题。不知道这是否是这样做的方式,但是 cmets 无法支持那么多字符?
  • 其实我想知道你是如何定义 TabItem.Resources 的......你已经将代码两次添加到 TabItem Style
  • 对不起。这就是我定义 TabItem 的方式: TabItem1
【解决方案2】:

您只需将TabItem.DataContext 设置为包含TextBlockImage 控件值的对象:

在代码中:

public class TabItemData
{
    public string ImageSource { get; set; }
    public string Heading { get; set; }
}

在 XAML 中的 Style 中:

<StackPanel Orientation="Horizontal">
    <Image Margin="10,0,0,0" Height="40" Width="40" Source="{Binding ImageSource}"/>
    <TextBlock Text="{Binding Heading}" VerticalAlignment="Center" 
        Style="{StaticResource Heading2}" Margin="10,0,0,0"/>
</StackPanel>

在您的视图模型中:

public class TabControlViewModel
{
    public TabControlViewModel()
    {
        TabItemData = new TabItemData() { Header = "Some header", 
            ImageSource = "Images/IconLeafGrey.png" };
    }

    public TabItemData TabItemData { get; set; }
}

在 XAML 中:

<TabItem DataContext="{Binding TabItemData}">
    ...
</TabItem>

当然,我省略了一些数据对象的初始化和你应该实现的INotifyPropertyChanged 接口,但我希望你能明白。

【讨论】:

    猜你喜欢
    • 2020-12-19
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    相关资源
    最近更新 更多