将非项值传递给项模板中的属性

本文关键字:属性 值传 | 更新日期: 2023-09-27 18:37:02

今天,我在将值从父控件向下传递到列表中子控件的属性时遇到问题。

有一个自定义控件,我制作了它作为缩略图复选框的功能。从本质上讲,它只是一个包裹在带有一些漂亮边框的图像上的复选框。它全部包装到 DLL 中,并部署为自定义控件

如果我想使用控件的单个实例,我可以像这样这样做......

<tcb:ThumbnailCheckBox IsChecked="True"
                       ImagePath="D:'Pictures'123.jpg"
                       CornerRadius="10"
                       Height="{Binding ThumbnailSize}"
                       Margin="10" />

代码 1 - 一次性使用

这很好用,并且可以轻松地绑定到我的 ViewModel 上的缩略图大小,因此我可以根据需要更改控件中图像的大小。

问题是当我想将此控件的使用扩展到列表中时,我遇到了一些问题。

首先,我已经设置了列表框控件的样式以满足我的需求,如下所示...

<Style TargetType="{x:Type ListBox}"
       x:Key="WrappingImageListBox">
    <!-- Set the ItemTemplate of the ListBox to a DataTemplate 
       which explains how to display an object of type BitmapImage. -->
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <tcb:ThumbnailCheckBox ImagePath="{Binding ImagePath}"
                                       IsChecked="{Binding Selected}"
                                       Height="{TemplateBinding utilities:MyAttachedProperties.ImageSize}"
                                       CornerRadius="8"
                                       Margin="10">
                </tcb:ThumbnailCheckBox>
            </DataTemplate>
        </Setter.Value>
    </Setter>
    <!-- Swap out the default items panel with a WrapPanel so that
       the images will be arranged with a different layout. -->
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <WrapPanel />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <!-- Set this attached property to 'Disabled' so that the 
       ScrollViewer in the ListBox will never show a horizontal 
       scrollbar, and the WrapPanel it contains will be constrained 
       to the width of the ScrollViewer's viewable surface. -->
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
            Value="Disabled" />
</Style>

代码清单 2 - 列表框样式

我从我的主要观点来看是这样称呼它的......

<ListBox ItemsSource="{Binding DirectoryPictures}"
         Grid.Row="1"
         Style="{DynamicResource WrappingImageListBox}"
         Background="Transparent" 
         util:MyAttachedProperties.ImageSize="500"/>

代码 3 - 主调用

这完全按照我的意愿工作,除了ImageSize属性。ImagePathSelected 都是绑定到ListBox的各个列表项的属性。

如您所见,我创建了一个附加属性来尝试传递值 ( 500 ),但它似乎不起作用。我应该注意,我认为我创建的样式是正确的,因为元素使用默认值。

public static class MyAttachedProperties
{
    public static double GetImageSize(DependencyObject obj)
    {
        return (double)obj.GetValue(ImageSizeProperty);
    }
    public static void SetImageSize(DependencyObject obj, double value)
    {
        obj.SetValue(ImageSizeProperty, value);
    }
    public static readonly DependencyProperty ImageSizeProperty =
        DependencyProperty.RegisterAttached(
            "ImageSize",
            typeof(double),
            typeof(MyAttachedProperties),
            new FrameworkPropertyMetadata(50D));
}

代码清单 4 - 附加属性

最后一行指定的50D将应用于列出的控件。如果我更改它并重新编译,最终结果会发生变化。但是我在 ListBox Main 调用(清单 3)中指定的 500 的发送值永远不会发送。当然,我最终想将视图模型上的500更改为绑定属性,但在我让它使用显式值之前,我不会这样做。

有人可以帮助我弄清楚如何从我的主ListBox调用(清单 3)发送值并将其应用于模板填充的各个项目吗?我有其他属性,但它们是我绑定到ListBox的列表中的每个项目的属性,而ImageSize不是。


编辑以解决第一响应

这似乎有效,但它有点奇怪。我的列表框现在被这样称呼...

<ListBox ItemsSource="{Binding DirectoryPictures}"
         Grid.Row="1"
         Style="{DynamicResource WrappingImageListBox}"
         Background="Transparent" />

我已经将我的风格更改为您建议的代码...

<tcb:ThumbnailCheckBox ImagePath="{Binding ImagePath}"
                       IsChecked="{Binding Selected}"
                       Height="{Binding Path=DataContext.ThumbnailSize, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}"
                       CornerRadius="8"
                       Margin="10">

我唯一担心的是,现在样式是直接访问该控件的 ViewModel,而不是接收绑定值。

假设我想再次使用该ListBox,但在另一个UserControl上,其ViewModel没有ThumbnailSize属性,而是用另一个名称使用?

你看我要去哪里...当前解决方案的可扩展性不强,并且仅限于当前类,因为它们是精确命名的。

事实上,在一个完美的世界中,我希望ImagePathSelected属性具有变量名称,但这是一个不同的讨论。

将非项值传递给项模板中的属性

可以使用

FindAncestor .其思想是,子遍历逻辑树,并尝试查找具有具体类型的父级(在本例中为 ListBox),然后访问附加属性。有关更多绑定表达式,请参阅 http://wpftutorial.net/BindingExpressions.html。

在您的ItemTemplate中,这是您可以访问ThumbnailSize财产的方式:

{Binding Path=(util:MyAttachedProperties.ImageSize), 
         RelativeSource={RelativeSource 
                           Mode=FindAncestor,
                           AncestorType={x:Type ListBox}}} 

从本质上讲,这里提出的问题有点相反,但结果是相同的。"ListBox中的项目怎么可能访问ListBox(附加的)属性。