如何在ListBox项目实例之间共享资源?

时间:2012-12-03 22:31:11

标签: wpf listbox itemscontrol shared-resource

我们有一个自定义渲染的ListBox,它维护一个基于宽度的StreamGeometry对象的实例。然后,控件需要与其所有项共享该StreamGeometry实例以进行渲染。

我们可以想到的唯一方法是将StreamGeometry实例放在ListBox的ViewModel中,然后在单个DataTemplates中绑定它,这对我来说感觉很脏,因为它只是一个视图,因此不应该在完全是ViewModel。

注意:我们也可以通过ListBox(或ListBox的子类)上的附加属性来存储它,但是我们仍然保留了一个仅查看的东西的绑定,这对我来说似乎是错误的。< / p>

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

您可以将StreamGeometry作为自定义列表视图的依赖项属性,然后通过Binding MyGeometry, RelativeSource={RelativeSource AncestorType=ListView}引用它。

这样,就没有涉及ViewModel。

enter image description here enter image description here

Xaml:

<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"
                xmlns:s="clr-namespace:System;assembly=mscorlib"
                Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <!-- default lsitviewitem style except for added path -->
        <Style TargetType="{x:Type ListViewItem}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
            <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
            <Setter Property="Padding" Value="2,0,0,0"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListViewItem}">
                        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                            <StackPanel Orientation="Horizontal">
                                <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                <!-- added path-->
                                <Path Stretch="Uniform" Stroke="DarkBlue" Fill="DarkOrchid" Data="{Binding MyGeometry, RelativeSource={RelativeSource AncestorType=ListView}}" />
                            </StackPanel>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected" Value="true">
                                <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                            </Trigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsSelected" Value="true"/>
                                    <Condition Property="Selector.IsSelectionActive" Value="false"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
                            </MultiTrigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid >
        <local:CustomListView Margin="20" >
            <local:CustomListView.Items>
                <ListViewItem Content="ListViewItem1" />
                <ListViewItem Content="ListViewItem2" />
                <ListViewItem Content="ListViewItem3" />
            </local:CustomListView.Items>
        </local:CustomListView>
    </Grid>
</Window>

CustomListView:

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

namespace WpfApplication1
{
    public class CustomListView : ListView
    {
        public StreamGeometry MyGeometry { get { return (StreamGeometry)GetValue(MyGeometryProperty); } set { SetValue(MyGeometryProperty, value); } }
        public static readonly DependencyProperty MyGeometryProperty = DependencyProperty.Register("MyGeometry", typeof(StreamGeometry), typeof(CustomListView), new PropertyMetadata(null));

        protected override void OnRender(DrawingContext drawingContext)
        {
            StreamGeometry geometry = new StreamGeometry(); // directly opening MyGeometry results in "must have isfrozen set to false to modify" error
            using (StreamGeometryContext context = geometry.Open()) 
            {
                Point p1 = new Point(this.ActualWidth * (2d / 5d), 0);
                Point p2 = new Point(this.ActualWidth / 2d, -10);
                Point p3 = new Point(this.ActualWidth * (3d / 5d), 0);

                context.BeginFigure(p1, true, true);

                List<Point> points = new List<Point>() { p2, p3 };
                context.PolyLineTo(points, true, true);
            }

            drawingContext.DrawGeometry(Brushes.DarkOrchid, new Pen(Brushes.DarkBlue, 1), geometry);

            this.MyGeometry = geometry;

            base.OnRender(drawingContext);
        }
    }
}