WPF XAML 资源对象仅可见一次

WPF XAML Resource Object Is Only Visible Once

尝试了几个小时都没有成功,很想知道为什么三个按钮中只有一个显示图标 ViewBox 内容。

我觉得我对控件模板的内部工作原理还不够了解。

第一个文件 ButtonProperties class 是包含 Icon ViewBox 的附件 属性 的所有者。 第二个文件是我的 MainWindow.xaml Window,它应该显示 3 个带有 Viewbox 图标的按钮。但只有最后一个按钮实例显示 Viewbox 图标。

感谢您的帮助。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace WpfApp1
{
    public class ButtonProperties : DependencyObject
    { 

        public static readonly DependencyProperty IconViewboxProperty = DependencyProperty.RegisterAttached("IconViewbox",
            typeof(Viewbox), typeof(ButtonProperties), new PropertyMetadata(null));

        public static void SetIconViewbox(DependencyObject obj, Viewbox viewbox)
        {
            obj.SetValue(IconViewboxProperty, viewbox);
        }

        public static Viewbox GetIconViewbox(DependencyObject obj)
        {
            return (Viewbox) obj.GetValue(IconViewboxProperty);
        }
    }
}

MainWindow.xaml

<Window
    x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApp1"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>
        <ResourceDictionary>
            <Viewbox x:Key="IconTrash">
                <Canvas Width="24" Height="24">
                    <Path Data="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z" Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
                </Canvas>
            </Viewbox>

            <Style x:Key="ButtonIcon" TargetType="Button">
                <Setter Property="Background" Value="Transparent" />
                <Setter Property="Foreground" Value="Black" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Border Background="{TemplateBinding Background}">
                                <ContentControl x:Name="IconControl" Content="{Binding Path=(local:ButtonProperties.IconViewbox), RelativeSource={RelativeSource TemplatedParent}}" />
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="IconControl" Property="Opacity" Value="0.5" />
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

            <Style
                x:Key="ButtonIconTrash"
                BasedOn="{StaticResource ButtonIcon}"
                TargetType="Button">
                <Setter Property="local:ButtonProperties.IconViewbox" Value="{DynamicResource IconTrash}" />
            </Style>
        </ResourceDictionary>
    </Window.Resources>

    <StackPanel Orientation="Vertical">
        <Button
            Width="25"
            Height="25"
            Style="{DynamicResource ButtonIconTrash}" />
        <Button
            Width="25"
            Height="25"
            Style="{DynamicResource ButtonIconTrash}" />
        <Button
            Width="25"
            Height="25"
            Style="{DynamicResource ButtonIconTrash}" />
    </StackPanel>
</Window>



默认情况下所有资源都是共享的。通常 XAML 处理器创建已定义资源的实例,例如 DataTemplate 并重用它。但是如果资源直接添加到对象图中,并且由于默认情况下 XAML 处理器总是创建资源的单个实例并在整个范围内共享它,该实例只能是 XAML 的一部分一次对象图。
换句话说,直接添加到对象图(可视树或在 FrameworkElement 的情况下也是逻辑树)的 Visual 实例不能同时出现在该图中的多个位置。

您必须通过将元素的 x:Shared 属性设置为 false 来明确禁用共享。这会强制 XAML 处理器为对象图中的每个事件创建一个新的资源实例:

<Viewbox x:Key="IconTrash" x:Shared="False">
  <Canvas Width="24" Height="24">
    <Path Data="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z" Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}" />
  </Canvas>
</Viewbox>