2009-09-09 52 views
2

我有一個自定義「PlanarMember」對象的集合,暴露了Boundary和Openings屬性。 Boundary屬性是一個自定義的「Polygon」類,用於公開頂點和段等。Openings是一個IEnumerable,基本上描述了較大多邊形中的開口。我可以保證開口不重疊/相交,外邊界是非自相交和閉合的,開口完全被外邊界包圍和其他合理的限制。如何繪製帶有開口的WPF多邊形?

我想創建一個WPF綁定,允許我使用Canvas的自定義ItemsPanel將這些對象放入ItemsControl集合中,這基本上意味着我需要能夠將自定義的PlanarMember對象轉換爲可以成爲WPF對象的WPF對象放置在畫布上,看起來像一個帶有開口的實心填充多邊形。該庫用於其他上下文,因此使用WPF類而不是原始PlanarMember是不可能的。將外部邊界表示爲WPF多邊形將是微不足道的,但是這是開啓了我的想法。有什麼想法嗎?

如果有幫助的話,我想表現的一些例子包括有窗戶和門洞的牆壁,有穿透的地板等等。我也不能僅僅在較大的形狀上畫出固體填充的形狀代表開口,因爲背後的物體需要通過孔來展示。

回答

1

經過一段時間的實驗後,我想出了一個滿足我需求的解決方案。我會在這裏張貼爲後人。希望它可以在這個問題上花費大約6個小時的時間來節省其他人。我用

夫婦類在別處定義:

  • PlanarElement:簡單地描述了一個2D的「東西」有邊界屬性暴露多邊形和開口財產暴露多邊形的IEnumerable對象列表
  • 多邊形:2D平面幾何類露出型的IEnumerable Point類型的屬性
  • :三維幾何點

這裏是解決方案:

1)這是到我PlanarMembers必將

<ItemsControl> 
<ItemsControl.Resources> 
    <DataTemplate DataType="{x:Type o:PlanarMember}"> 
     <Path Stroke="Black" StrokeThickness="1" 
       Data="{Binding Converter={StaticResource PlanarMemberConverter}}"> 
      <Path.Fill> 
       <SolidColorBrush Opacity="0.5" Color="LightGray" /> 
      </Path.Fill> 
     </Path> 
    </DataTemplate> 
</ItemsControl.Resources> 
<ItemsControl.ItemsPanel> 
    <ItemsPanelTemplate> 
     <Canvas RenderTransform="{StaticResource CurrentDisplayTransform}"/> 
    </ItemsPanelTemplate> 
</ItemsControl.ItemsPanel> 
</ItemsControl> 

2)注意在Path的數據設定使用PlanarMemberConverter的ItemsControl的,在這裏創建:

<this:PlanarMemberConverter x:Key="PlanarMemberConverter" /> 

3)實際的IValueCo此處定義了逆變器派生類:

[ValueConversion(typeof(PlanarMember), typeof(Geometry))] 
class PlanarMemberConverter : IValueConverter 
{ 

#region IValueConverter Members 

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
{ 
    if (targetType != typeof(Geometry)) return null; 
    var planarMember = value as PlanarMember; 

    var collection = new PathFigureCollection(planarMember.Openings.Count() + 1) 
         { 
          new PathFigure(
           planarMember.Boundary.Vertices.First().AsPoint(), 
           ToSegments(planarMember.Boundary.Vertices), true){IsFilled = true} 
         }; 

    foreach (var opening in planarMember.Openings) 
    { 
     collection.Add(new PathFigure(
          opening.Vertices.First().AsPoint(), 
          ToSegments(opening.Vertices), true) { IsFilled = true }); 
    } 

    return new PathGeometry(collection) {FillRule = FillRule.EvenOdd}; 
} 

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
{ 
    throw new NotImplementedException(); 
} 

#endregion 

public IEnumerable<PathSegment> ToSegments(IEnumerable<Point> points) 
{ 
    return 
     from point in points 
     select (PathSegment)new LineSegment(point.AsPoint(), true); 
} 
}