2012-12-03 98 views
2

我们有一个自定义呈现的ListBox,它维护基于其宽度的StreamGeometry对象的实例。该控件需要随后将该StreamGeometry实例与其所有项目共享以用于呈现目的。如何在ListBox项目实例之间共享资源?

我们可以考虑的唯一方法是将StreamGeometry实例放入ListBox的ViewModel中,然后绑定到单个DataTemplates中,这对我来说只是感觉很脏,因为考虑到这是一个只能查看的东西,因此不应该是在ViewModel中。注意:我们也可以通过ListBox(或ListBox的子类)上的附加属性来存储它,但是我们仍然留有绑定的仅限视图的东西,这对我来说似乎是错误的。

有什么想法?

+0

什么'Window.Resources'? – Clemens

+0

不,因为它的ListBox-instance具体可以有很多。另外,它是由ListBox的属性决定的。我的实际问题是通过数据模板实际共享项目本身。我的意思是,即使是正确的做法呢?我认为绑定可能会很慢。 – MarqueIV

+0

资源字典中的对象(例如PathGeometry,如果这是您所指的GraphicsPath)可以由您喜欢的任意数量的ListBoxItems共享。 – Clemens

回答

0

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

这样,就没有涉及的ViewModel。

enter image description hereenter 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); 
     } 
    } 
} 
+0

这与我在问题中提到的类似;唯一的区别是我说的是使用附加属性,而你使用了子类。另外,我们不希望使用这样的绑定,因为我们在使用路径的ListBoxItems中进行自定义渲染,而使用可视化树,我相信*会混淆UI(我们的路径非常复杂)。 (我把这个星号放进去,因为在引擎盖下,渲染可能实际上是在建立可视化树本身,这意味着我的陈述只是部分正确的。在那里我需要更多的研究。) – MarqueIV

+0

看起来,重新瞄准。我试图理解:当你说你是自定义渲染你的列表框,这不需要一个子类,所以你不覆盖OnRender方法?什么意思是“混乱”UI,反应迟钝?我认为我的方法,有一个共享路径实例。如果要自定义渲染而不是直接将其放置在可视化树中,可以将其绑定到CustomListViewItem的属性。至于绑定,我绝对不理解你的关注。这是绑定到另一个视觉的DP,与Data/ViewModel无关! –

+0

我们正在通过'ItemContainerStyle'应用的ListBoxItem的子类中进行自定义渲染。然而,我们希望ListBoxItem的每个ListBoxItem *能够共享一个路径,因此ListBox自然必须保存该路径的实例。我只是想知道是否有一个好的方法来做到这一点。你的方式会起作用,就像一个附属的财产一样。我只是讨厌使用绑定来实现它,更不用说使用RelativeSource了,但我不知道有什么其他方式让ListBoxItem去实现它。 (然后,我认为它确实对ItemsControl有一定的参考) – MarqueIV