我有一组自定义的“PlanarMember”对象,它们暴露了Boundary和Openings属性。 Boundary属性是一个自定义的“Polygon”类,用于显示顶点和线段等.Opennings是一个IEnumerable,基本上描述了较大多边形中的开口。我可以保证开口不重叠/交叉,外边界是非自相交和闭合的,开口完全被外边界所包含,还有其他合理的限制。
我想创建一个WPF绑定,允许我将这些对象抛出到带有Canvas的自定义ItemsPanel的ItemsControl集合中,这基本上意味着我需要能够将我的自定义PlanarMember对象转换为可以放置的WPF对象在画布上,看起来像一个带有开口的实心填充多边形。此库在其他上下文中使用,因此使用WPF类而不是原始PlanarMember是不可能的。将外边界表示为WPF多边形将是微不足道的,但它是让我失望的开口。有什么想法吗?
如果它有所帮助,我试图表示的一些例子包括带有窗户和门洞的墙,带有穿透的楼板等。我也不能只在较大的形状上绘制实心填充的形状代表开口,因为后面的物体需要通过这些孔来显示。
答案 0 :(得分:1)
经过一段时间的实验,我想出了一个满足我需求的解决方案。我会在这里张贴后代。希望它可以节省6个小时左右的其他人,我已经花在这个问题上了。
我使用的偶然类在其他地方定义:
以下是解决方案:
1)以下是我的PlanarMembers将被绑定的ItemsControl
<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:
<this:PlanarMemberConverter x:Key="PlanarMemberConverter" />
3)这里定义了实际的IValueConverter派生类:
[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);
}
}