gpt4 book ai didi

c# - 从附加属性设置 WPF MenuItem 图标样式

转载 作者:行者123 更新时间:2023-11-30 23:10:07 24 4
gpt4 key购买 nike

我正在尝试将一些定义 MenuItem 的 XAML 移动到 Style 中。

我有以下工作 XAML:

<Menu x:Name="menu" Height="19" Margin="10,10,10.333,0" VerticalAlignment="Top">
<MenuItem Header="_Open">
<MenuItem.Icon>
<Viewbox>
<ContentControl Content="{DynamicResource appbar.folder.open}" RenderTransformOrigin="0.5,0.5">
<ContentControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</TransformGroup>
</ContentControl.RenderTransform>
</ContentControl>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</Menu>

资源看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Key="appbar.folder.open" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="44" Height="26" Canvas.Left="19" Canvas.Top="24" Stretch="Fill" Fill="#FF000000" Data="F1 M 19,50L 28,34L 63,34L 54,50L 19,50 Z M 19,28.0001L 35,28C 36,25 37.4999,24.0001 37.4999,24.0001L 48.75,24C 49.3023,24 50,24.6977 50,25.25L 50,28L 53.9999,28.0001L 53.9999,32L 27,32L 19,46.4L 19,28.0001 Z "/>
</Canvas>
</ResourceDictionary>

作为旁注,我也不知道如何摆脱显式缩放。这似乎是一个小问题,但如果这也能得到解决,我将不胜感激。

无论如何,为了尽可能多地将这种过于表达的定义移动到样式中,我为 Visual 类型的附加属性创建了代码

namespace extensions
{
public class AttachedProperties
{
public static readonly DependencyProperty VisualIconProperty =
DependencyProperty.RegisterAttached("VisualIcon",
typeof(System.Windows.Media.Visual), typeof(AttachedProperties),
new PropertyMetadata(default(System.Windows.Media.Visual)));

public static void SetVisualIcon(UIElement element, System.Windows.Media.Visual value)
{
element.SetValue(VisualIconProperty, value);
}
public static System.Windows.Media.Visual GetVisualIcon(UIElement element)
{
return (System.Windows.Media.Visual)element.GetValue(VisualIconProperty);
}
}
}

重新定义菜单项

<MenuItem Header="_Open"
Style="{StaticResource MenuItemStyle}"
extensions:AttachedProperties.VisualIcon="{DynamicResource appbar.folder.open}" />

并尝试创建一个 Style 读取 VisualIcon 属性来设置图标内容

<Style x:Key="MenuItemStyle" TargetType="MenuItem">
<Setter Property="MenuItem.Icon">
<Setter.Value>
<Viewbox>
<ContentControl RenderTransformOrigin="0.5,0.5">
<ContentControl.Content>
<!-- this would work but doesn't reference the VisualIcon property.. <DynamicResource ResourceKey="appbar.folder.open"/> -->
<!-- these do not -->
<Binding Path="(extensions:AttachedProperties.VisualIcon)" RelativeSource="{RelativeSource FindAncestor, AncestorType=MenuItem}"/>-->
<!--<Binding Path="(extensions:AttachedProperties.VisualIcon)" RelativeSource="{RelativeSource TemplatedParent}"/>-->
<!--<Binding Path="(extensions:AttachedProperties.VisualIcon)" RelativeSource="{RelativeSource Self}"/>-->
</ContentControl.Content>
<ContentControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</TransformGroup>
</ContentControl.RenderTransform>
</ContentControl>
</Viewbox>
</Setter.Value>
</Setter>
</Style>

但失败了。使用 DynamicResource 和静态键引用资源是可行的,但我无法使用附加属性进行任何绑定(bind)。

因为我是 WPF 初学者,我不确定这是否是一个好方法。

[编辑1]

我测试了所有提供的解决方案。 Grek40answer没有为我显示任何图标,无论是在设计 View 中还是在运行时;也许我做错了什么。

grx70 中的第二种方法的 second answer它对我来说是最有前途的,因为它可以在设计 View 和运行时可靠地显示图标。但是,我不明白Win7和Win10之间似乎存在差异。我在 Win7 和 Win10 上测试了相同的源(在外部驱动器上)。对于 Win10,它看起来不错,但是 Win7 绘制的图标太大了。

(注:原因在this comment中给出)

Difference Win7/Win10

这是窗口测试代码:

<Window.Resources>
<Style x:Key="MenuItemStyle" TargetType="controls:MenuItemEx">
<Setter Property="MenuItem.Icon">
<Setter.Value>
<Viewbox>
<ContentControl RenderTransformOrigin="0.5,0.5">
<ContentControl.Content>
<Binding Path="(extensions:AttachedProperties.VisualIcon)" RelativeSource="{RelativeSource FindAncestor, AncestorType=MenuItem}"/>
</ContentControl.Content>
<ContentControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</TransformGroup>
</ContentControl.RenderTransform>
</ContentControl>
</Viewbox>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MenuItemStyle2" TargetType="MenuItem">
<Setter Property="uihelpers:MenuItemHelper.IsEnabled" Value="True" />
<Setter Property="MenuItem.Icon">
<Setter.Value>
<Viewbox>
<ContentControl RenderTransformOrigin="0.5,0.5"
Content="{Binding
Path=(uihelpers:MenuItemHelper.MenuItem).(extensions:AttachedProperties.VisualIcon),
RelativeSource={RelativeSource AncestorType=Viewbox}}">
<ContentControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</TransformGroup>
</ContentControl.RenderTransform>
</ContentControl>
</Viewbox>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="MenuItemStyle3" TargetType="{x:Type MenuItem}">
<Style.Resources>
<DataTemplate x:Key="MenuItemStyle3dt" DataType="{x:Type Style}">
<Path Style="{Binding}"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DataTemplate>
</Style.Resources>
</Style>
<Style x:Key="appbar.folder.open.style3.local" TargetType="{x:Type Path}">
<Setter Property="Fill" Value="Black" />
<Setter Property="Data" Value="M0,26 L9,10 L44,10 L35,26 Z M0,4 L16,4 C17,1 18.5,0 18.5,0 L29.75,0 C30.3,0 31,0.7 31,1.25 L31,4 L34,4 L34,8 L8,8 L0,22.4 Z" />
</Style>
<extensions:PathStyle x:Key="appbar.folder.open.style3b">
<Setter Property="Path.HorizontalAlignment" Value="Center" />
<Setter Property="Path.VerticalAlignment" Value="Center" />
<Setter Property="Path.Stretch" Value="Uniform" />
<Setter Property="Path.Fill" Value="Black" />
<Setter Property="Path.Data" Value="M0,26 L9,10 L44,10 L35,26 Z M0,4 L16,4 C17,1 18.5,0 18.5,0 L29.75,0 C30.3,0 31,0.7 31,1.25 L31,4 L34,4 L34,8 L8,8 L0,22.4 Z" />
</extensions:PathStyle>
<DataTemplate DataType="{x:Type extensions:PathStyle}">
<Path Style="{Binding}" />
</DataTemplate>

<Canvas x:Key="appbar.folder.open.style4.local" x:Shared="False" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="44" Height="26" Canvas.Left="19" Canvas.Top="24" Stretch="Fill" Fill="#FF000000" Data="F1 M 19,50L 28,34L 63,34L 54,50L 19,50 Z M 19,28.0001L 35,28C 36,25 37.4999,24.0001 37.4999,24.0001L 48.75,24C 49.3023,24 50,24.6977 50,25.25L 50,28L 53.9999,28.0001L 53.9999,32L 27,32L 19,46.4L 19,28.0001 Z "/>
</Canvas>
<Viewbox x:Key="MenuItemStyle4.Icon" x:Shared="False">
<ContentControl Content="{Binding Path=Tag,RelativeSource={RelativeSource AncestorType=MenuItem}}" RenderTransformOrigin="0.5,0.5">
<ContentControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</TransformGroup>
</ContentControl.RenderTransform>
</ContentControl>
</Viewbox>
<Style x:Key="MenuItemStyle4" TargetType="MenuItem">
<Setter Property="Icon" Value="{StaticResource MenuItemStyle4.Icon}"/>
</Style>
</Window.Resources>
<Grid>
<Menu x:Name="menu" Height="19" Margin="10,10,10.333,0" VerticalAlignment="Top">
<MenuItem Header="_File">
<controls:MenuItemEx Header="_Open"
Style="{StaticResource MenuItemStyle}"
extensions:AttachedProperties.VisualIcon="{DynamicResource appbar.folder.open}" />
<MenuItem Header="_Open"
Style="{StaticResource MenuItemStyle2}"
extensions:AttachedProperties.VisualIcon="{DynamicResource appbar.folder.open}" />
<MenuItem Header="_Open"
Style="{StaticResource MenuItemStyle3}"
Icon="{DynamicResource appbar.folder.open.style3}" />
<MenuItem Header="_Open"
Style="{StaticResource MenuItemStyle3}"
Icon="{DynamicResource appbar.folder.open.style3.local}" />
<MenuItem Header="_Open" Icon="{DynamicResource appbar.folder.open.style3b}" />
<MenuItem Header="_Open"
Style="{StaticResource MenuItemStyle4}"
Tag="{DynamicResource appbar.folder.open}" />
<MenuItem Header="_Open"
Style="{StaticResource MenuItemStyle4}"
Tag="{DynamicResource appbar.folder.open.style4.local}" />
<MenuItem Header="_Save">
<MenuItem.Icon>
<Viewbox>
<ContentControl Content="{DynamicResource appbar.save}" RenderTransformOrigin="0.5,0.5">
<ContentControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</TransformGroup>
</ContentControl.RenderTransform>
</ContentControl>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
<Menu x:Name="menu2" Height="19" Margin="9,32,11.333,0" VerticalAlignment="Top" ItemContainerStyle="{StaticResource MenuItemStyle4}">
<MenuItem Header="_File">
<MenuItem Header="_Open"
Tag="{DynamicResource appbar.folder.open.style4.local}" />
<MenuItem Header="_Open"
Tag="{DynamicResource appbar.folder.open}" />
</MenuItem>
</Menu>
</Grid>

这是全局资源:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Key="appbar.folder.open" x:Shared="False" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="44" Height="26" Canvas.Left="19" Canvas.Top="24" Stretch="Fill" Fill="#FF000000" Data="F1 M 19,50L 28,34L 63,34L 54,50L 19,50 Z M 19,28.0001L 35,28C 36,25 37.4999,24.0001 37.4999,24.0001L 48.75,24C 49.3023,24 50,24.6977 50,25.25L 50,28L 53.9999,28.0001L 53.9999,32L 27,32L 19,46.4L 19,28.0001 Z "/>
</Canvas>
<Style x:Key="appbar.folder.open.style3" TargetType="{x:Type Path}">
<Setter Property="Fill" Value="Black" />
<Setter Property="Data" Value="M0,26 L9,10 L44,10 L35,26 Z M0,4 L16,4 C17,1 18.5,0 18.5,0 L29.75,0 C30.3,0 31,0.7 31,1.25 L31,4 L34,4 L34,8 L8,8 L0,22.4 Z" />
</Style>
</ResourceDictionary>

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Key="appbar.save" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="34.8333" Height="34.8333" Canvas.Left="20.5833" Canvas.Top="20.5833" Stretch="Fill" Fill="#FF000000" Data="F1 M 20.5833,20.5833L 55.4167,20.5833L 55.4167,55.4167L 45.9167,55.4167L 45.9167,44.3333L 30.0833,44.3333L 30.0833,55.4167L 20.5833,55.4167L 20.5833,20.5833 Z M 33.25,55.4167L 33.25,50.6667L 39.5833,50.6667L 39.5833,55.4167L 33.25,55.4167 Z M 26.9167,23.75L 26.9167,33.25L 49.0833,33.25L 49.0833,23.75L 26.9167,23.75 Z "/>
</Canvas>
</ResourceDictionary>

合并到 app.xaml 中:

<Application.Resources>
<ResourceDictionary >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="icons/appbar.folder.open.xaml"/>
<ResourceDictionary Source="icons/appbar.save.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

图标偏移的原因是我从 github.com/Templarian/WindowsIcons 中或多或少地以 1:1 的比例获取了它们。并希望因为它们是以这种格式提供的(我也尝试将它们保存为画笔,首先使用 Inkscape 然后使用 Expression Design)这样使用它们会很常见。

最佳答案

因为它有点像 XY problem ,我会为您提供替代方法来实现您的目标。

首先,您的 appbar.folder.open资源过于复杂。 Canvas是完全多余的(您可以通过设置其 Path 来抵消您的 Margin )。这些数字在 Path 内偏移通过 19,24 ,与 Path 相结合在 Canvas 中被抵消导致有必要使用 Viewbox连同 ScaleTransform .此外,您的资源不可重用,因为它只能加载到可视化树中一次,因此它只会在最后一次被引用的地方可见(它将在之前的所有地方卸载)。我的建议是创建一个 Style对于 Path相反 - 它不仅可重用,而且在您可以修改目标上的其他属性的意义上也是可扩展的 Path应用样式后。这是完成这项工作的最小样式(我已经翻译了您的数据,因此它不再偏移):

<Style x:Key="appbar.folder.open" TargetType="{x:Type Path}">
<Setter Property="Fill" Value="Black" />
<Setter Property="Data" Value="M0,26 L9,10 L44,10 L35,26 Z M0,4 L16,4 C17,1 18.5,0 18.5,0 L29.75,0 C30.3,0 31,0.7 31,1.25 L31,4 L34,4 L34,8 L8,8 L0,22.4 Z" />
</Style>

其次,我不太明白你AttachedProperties.VisualIcon的目的。附属属性(property)。在我的方法中,它是完全多余的。另外,我相信这是使设计器在禁用项目代码的情况下无法正确显示图标的部分。唯一的问题是如果我们设置 MenuItem.Icon="{DynamicResource appbar.folder.open}"我们会得到 System.Windows.Style显示文本而不是图标。和 DynamicResourceExtension不支持开箱即用地转换引用资源。但是,我们可以使用一个聪明的技巧来使事情正常进行——只需提供一个隐式的 DataTemplate。与 DataType="{x:Type Style}"将自动应用:

<Style x:Key="MenuItemStyle" TargetType="{x:Type MenuItem}">
<Style.Resources>
<DataTemplate DataType="{x:Type Style}">
<Path Style="{Binding}"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DataTemplate>
</Style.Resources>
</Style>

我们在 Path 上设置了一些额外的属性以便它适合图标区域。

我们现在需要做的就是引用样式和图标,使其显示在 MenuItem 上。 :

<Menu (...)>
<MenuItem Header="_Open"
Style="{StaticResource MenuItemStyle}"
Icon="{DynamicResource appbar.folder.open}" />
</Menu>

这种方法还有一个额外的优势,即即使在禁用项目代码的情况下,它也可以在设计器中工作(至少对我来说是这样)。

编辑

如果你想完全分离和自动化,你可以继承Style :

public class PathStyle : Style
{
public PathStyle()
{
TargetType = typeof(Path);
}
}

并提供隐含的DataTemplate在你的资源字典中:

<local:PathStyle x:Key="appbar.folder.open">
<Setter Property="Path.HorizontalAlignment" Value="Center" />
<Setter Property="Path.VerticalAlignment" Value="Center" />
<Setter Property="Path.Stretch" Value="Uniform" />
<Setter Property="Path.Fill" Value="Black" />
<Setter Property="Path.Data" Value="M0,26 L9,10 L44,10 L35,26 Z M0,4 L16,4 C17,1 18.5,0 18.5,0 L29.75,0 C30.3,0 31,0.7 31,1.25 L31,4 L34,4 L34,8 L8,8 L0,22.4 Z" />
</local:PathStyle>
<DataTemplate DataType="{x:Type local:PathStyle}">
<Path Style="{Binding}" />
</DataTemplate>

我移动了 DataTemplate 中的所有属性到 Style这样它就可以被其他样式覆盖。请注意,您需要完全限定属性名称,即使用 Path.Data而不是简单的 Data .

现在您需要做的就是在您的 View 中引用资源:

<MenuItem Icon="{DynamicResource appbar.folder.open}" (...) />

甚至:

<ContentPresenter Content="{DynamicResource appbar.folder.open}" />

所有的魔法都是由框架完成的。这种方法的美妙之处在于您可以替换您的 ResourceDictionary其中一个包含例如:

<Border x:Key="appbar.folder.open" x:Shared="False" Background="Red" />

无需修改 View ,一切仍然有效。

关于c# - 从附加属性设置 WPF MenuItem 图标样式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45513566/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com