2012-12-03 190 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