【问题标题】:How to attach a property to an object using XAML如何使用 XAML 将属性附加到对象
【发布时间】:2012-01-01 23:38:52
【问题描述】:

我正在尝试格式化我的 ListBoxItem 模板以包含图像。我可以将图像添加到 ListBoxItem,但我不太确定如何设置该图像的值。

ListBoxItem 的模板:

        <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <Border Name="Border" Padding="2" SnapsToDevicePixels="true">
                        <StackPanel Orientation="Horizontal" >
                            <Image Source="{Binding Path=Source}" Height="16" Width="16" HorizontalAlignment="Center" VerticalAlignment="Center" />
                            <ContentPresenter Name="ContentPresenter" HorizontalAlignment="Stretch" Width="Auto" />
                        </StackPanel>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter TargetName="Border" Property="Background" Value="{StaticResource ListBoxItem_BackgroundBrush_Selected}"/>
                            <Setter TargetName="ContentPresenter" Property="TextElement.FontWeight" Value="Bold"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{StaticResource TabItem_BackgroundBrush_Disabled}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

示例列表框代码:

   <ListBox Name="listBox_LibAll" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
       <ListBoxItem Content="Item 1" />
       <ListBoxItem Content="Item 2" />
       <ListBoxItem Content="Item 3" />                                
   </ListBox>

输出:

如果你看图片你会注意到图片有一个地方,我只是不知道如何设置它的值。我在想我可以以某种方式将“源”属性附加到 ListBoxItem

【问题讨论】:

    标签: wpf xaml wpf-controls


    【解决方案1】:

    您可以将RelativeSource 绑定到Tag 或一些attached property

    Source="{Binding Tag, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
    
    <ListBoxItem Tag="SomePath" />
    
    Source="{Binding (ns:AttachedProperties.Source), RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
    
    <ListBoxItem ns:AttachedProperties.Source="SomePath" />
    

    您还可以使用here 所示的动态资源。

    然而,最简洁的解决方案是使内容复杂化,即使 ListBoxItem 主机成为 UserControl 或自定义控件,例如实际上具有图像的 proper 属性。你通常也不应该覆盖ListBoxItems的控件模板,而是使用ListBox的ItemTemplatedata template数据。

    【讨论】:

    • 谢谢,这很好用。它也很容易在 c# 中使用。谢谢,
    • @Dmitry: 一些XML namespace 需要定义为指向定义包含附加属性的类的 CLR 命名空间。
    • @zaza:我添加了另一段,因为我认为您采用了错误的方法,我之前的建议有效,但我不会真正推荐它们,使用数据模板(即复杂内容)在我的意见。
    • @H.B.如果我使用您的第一种方法,有什么问题吗?我刚刚用我自己的自定义控件对其进行了测试,我发现它使内存使用量增加了 8MB(ListBox 中的 610 个项目)。该程序旨在在 ListBox 中包含数千个项目。此外,我不需要将Tag 属性用于任何其他目的。
    • @zaza:如果您不同时覆盖控件模板,通常应该不会很戏剧化(因为您将拥有相同的控件,但在另一个地方)。无论哪种方式,如果您有数千个项目,则无论如何都应该使用虚拟化,以便只创建可见的项目。
    【解决方案2】:

    你快到了。

    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
        }
    
        public class ImageItem: DependencyObject
        {
            public static readonly DependencyProperty SourceProperty =
                DependencyProperty.RegisterAttached("Source",
                typeof(string),
                typeof(DependencyObject),
                new PropertyMetadata((o, e) => 
                {
                    //System.Diagnostics.Debugger.Break();
                }));
    
            public static string GetSource(DependencyObject o)
            {
                return (string)o.GetValue(ImageItem.SourceProperty);
            }
    
            public static void SetSource(DependencyObject o, string e)
            {
                o.SetValue(ImageItem.SourceProperty, e);
            }
        }
    }
    

    标记:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.Resources>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ListBoxItem">
                                <Border Name="Border" Padding="2" SnapsToDevicePixels="true">
                                    <StackPanel Orientation="Horizontal" >
                                        <Image Source="{Binding Path=Source, 
                                               RelativeSource={RelativeSource AncestorType=ListBoxItem}}" 
                                               Height="16" 
                                               Width="16" 
                                               HorizontalAlignment="Center" VerticalAlignment="Center" />
                                        <ContentPresenter Name="ContentPresenter" HorizontalAlignment="Stretch" Width="Auto" />
                                    </StackPanel>
                                </Border>
                                <ControlTemplate.Triggers>
                                    <Trigger Property="IsSelected" Value="true">
                                        <Setter TargetName="Border" Property="Background" Value="{StaticResource ListBoxItem_BackgroundBrush_Selected}"/>
                                        <Setter TargetName="ContentPresenter" Property="TextElement.FontWeight" Value="Bold"/>
                                    </Trigger>
                                    <Trigger Property="IsEnabled" Value="false">
                                        <Setter Property="Foreground" Value="{StaticResource TabItem_BackgroundBrush_Disabled}"/>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Grid.Resources>
            <ListBox Name="listBox_LibAll" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <ListBoxItem local:ImageItem.Source="/WpfApplication1;component/Penguins.jpg" Content="Item 1" />
                <ListBoxItem Content="Item 2" />
                <ListBoxItem Content="Item 3" />
            </ListBox>
        </Grid>
    </Window>
    

    【讨论】:

    • 这里有几个问题。 1. ImageItem 不应该从任何东西继承,因为它不是一个对象。 2. ImageItem 应该是一个静态类,因为它的实例没有意义,它只是承载一个属性。 3. 属性的类型应该是ImageSource,在XAML中仍然可以分配一个字符串,但是你希望属性的类型安全。 4. 所有者类型应为ImageItem 而不是DepedencyObject,因为该属性已在该类中定义。 (另外我会说你的答案太吵了,太多(甚至是多余的和部分错误的)代码,解释太少了)
    • H.B. - 你是如何设法获得 30K 并且仍然有这样的问题的? ImageItems 必须从 DO 中获取,否则您将无法为其注册附加属性。 DO 允许最广泛的对象,这就是我使用它的原因。 Brr Grrr... 只需获取代码并编译它。至少我没用过 ns:) LOL。
    • 错误和错误,附加属性是附加的,它们不需要拥有类型是依赖对象。并且拥有类型与属性可以使用的地方不同,每个附加属性都可以在每个依赖对象上使用。
    • 嘿,我理解你的失望,你迷路了 2 个树林(甚至没有 3 个)。获取解决方案并了解如何使用 DP。请记住,批评总是比创造容易。
    • 这不是粗略的指导,如果被问者不知道如何定义附加属性,他可以在我提供的链接中轻松查找,我不需要添加那个多余的代码.
    猜你喜欢
    • 1970-01-01
    • 2023-03-05
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-24
    • 2011-07-03
    • 2011-10-11
    相关资源
    最近更新 更多