C# 在ItemsControl中使用GeometryDrawing

C# 在ItemsControl中使用GeometryDrawing,c#,wpf,performance,data-binding,itemscontrol,C#,Wpf,Performance,Data Binding,Itemscontrol,在我的WPF应用程序中,我使用了一个类的可观测集合,该类包含点集合。此点集合用于为可观察集合中的每个项目绘制多边形。下面的代码展示了如何使用模板绑定绘制所有多边形: <Grid> <ItemsControl ItemsSource="{Binding GeoLines}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <C

在我的WPF应用程序中,我使用了一个类的
可观测集合
,该类包含
点集合
。此点集合用于为可观察集合中的每个项目绘制多边形。下面的代码展示了如何使用模板绑定绘制所有多边形:

<Grid>
<ItemsControl ItemsSource="{Binding GeoLines}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type vm:GeoPointsViewModel}">
                <Polygon Stroke="LightSkyBlue" StrokeThickness="0.5" Opacity="0.8">                      
                    <Polygon.Style>
                        <Style TargetType="{x:Type Polygon}">
                            <Setter Property="Points">
                                <Setter.Value>
                                    <MultiBinding Converter="{StaticResource pointMultiConverter}">
                                        <Binding Path="ActualWidth" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Canvas}}"/>
                                        <Binding Path="ActualHeight" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Canvas}}"/>
                                        <Binding Path="Points"/>
                                    </MultiBinding>
                                </Setter.Value>
                            </Setter>
                            <Setter Property="Fill" Value="#FF0A0A10"/>                                
                        </Style>
                    </Polygon.Style>
                </Polygon>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>


虽然它工作得很好,但性能并不好,因为每个多边形都是一个
ui元素
,有着所有的铃铛和哨子。为了提高性能,我想使用占用空间较小的
GeometryDrawing
。不幸的是,我不知道在这种情况下如何进行数据绑定。因此,我的问题是如何使用
GeometryDrawing
(或者比
Shapes
更轻的东西)实现代码。

我不确定使用
GeometryDrawing
是否可以显著提高性能,但下面是如何实现它。结果可能不完全符合您的要求,这是因为
PathFigure
的默认
StartPoint

<DataTemplate DataType="{x:Type vm:GeoPointsViewModel}">
   <Border>
      <Border.Background>
         <DrawingBrush>
                <DrawingBrush.Drawing>
                    <GeometryDrawing Brush="Red">
                        <GeometryDrawing.Geometry>
                            <PathGeometry>
                                <PathFigure IsClosed="True">
                                    <PolyLineSegment Points="{Binding Points}"/>
                                </PathFigure>
                            </PathGeometry>
                        </GeometryDrawing.Geometry>
                    </GeometryDrawing>
                </DrawingBrush.Drawing>
          </DrawingBrush>
      </Border.Background>
   </Border>
</DataTemplate>


我对多段线使用了一个简单的
红色
。如果需要,还可以指定一些
笔。请注意,多边形的效果可能与原始代码产生的效果不完全相同。我想你可能需要做更多的调整才能把它做好。

我最终使用代码隐藏直接绘制视觉效果。这绕过了许多UI层,显著提高了性能。任何其他改进此代码的建议仍然是受欢迎的

    private Brush geoBrush = (SolidColorBrush)(new BrushConverter().ConvertFrom("#FF0A0A10"));
    private Pen geoPen = new Pen(Brushes.LightSkyBlue, 0.5);
    private DropShadowEffect geoDropShadow = new DropShadowEffect
    {
        Color = Brushes.LightSteelBlue.Color,
        BlurRadius = 8.0,
        ShadowDepth = 0.0
    };
    private DrawingVisual GeoVisual = null;
    private void UpdateGeoLines()
    {
        MapProjectionViewModel map = this.DataContext as MapProjectionViewModel;
        if (map != null)
        {
            DrawingVisual visual = new DrawingVisual();
            using (DrawingContext dc = visual.RenderOpen())
            {
                foreach (var item in map.GeoLines)
                {
                    if (item.Points.Count > 1)
                    {
                        List<Point> points = new List<Point>();
                        foreach (var p in item.Points)
                        {
                            Point point = new Point(
                            p.X * canvas.ActualWidth,
                            p.Y * canvas.ActualHeight);
                            points.Add(point);
                        }
                        StreamGeometry geom = new StreamGeometry();
                        using (StreamGeometryContext gc = geom.Open())
                        {
                            Point p1 = points[0];

                            // Start new object, filled=true, closed=true
                            gc.BeginFigure(p1, true, true);

                            // isStroked=true, isSmoothJoin=true
                            gc.PolyLineTo(points, true, false);
                        }
                        geom.Freeze();
                        dc.DrawGeometry(geoBrush, geoPen, geom);
                    }
                }
            }

            visual.Effect = geoDropShadow;
            visual.Opacity = 0.8;
            canvas.Visuals.Remove(GeoVisual);
            canvas.Visuals.Add(visual);
            GeoVisual = visual;
        }
    }
private Brush geoBrush=(SolidColorBrush)(新的BrushConverter().ConvertFrom(“#ff0a0a10a10”);
private Pen geoPen=新笔(画笔。浅天蓝,0.5);
私有DropShadowEffect geoDropShadow=新DropShadowEffect
{
颜色=画笔。LightSteelBlue.Color,
半径=8.0,
阴影深度=0.0
};
私有DrawingVisualGeoVisualic=null;
私有void updategolines()
{
MapProjectionViewModel map=this.DataContext作为MapProjectionViewModel;
if(map!=null)
{
DrawingVisual=新建DrawingVisual();
使用(DrawingContext dc=visual.renderropen())
{
foreach(map.GeoLines中的变量项)
{
如果(item.Points.Count>1)
{
列表点=新列表();
foreach(项目点中的var p)
{
点=新点(
p、 X*canvas.ActualWidth,
p、 Y*画布实际高度);
点。添加(点);
}
StreamGeometry geom=新的StreamGeometry();
使用(StreamGeometryContext gc=geom.Open())
{
点p1=点[0];
//启动新对象,填充=真,关闭=真
gc.BeginFigure(p1,true,true);
//isStroked=true,isSmoothJoin=true
gc.PolyLineTo(点,真,假);
}
geom.Freeze();
dc.绘图几何(geoBrush、geoPen、geom);
}
}
}
visual.Effect=geoDropShadow;
视觉不透明度=0.8;
canvas.Visuals.Remove(地理视觉);
canvas.Visuals.Add(可视);
地理视觉=视觉;
}
}

谢谢。不幸的是,这不起作用。即使这样,它也会为每个项目创建一个路径几何体,这正是我想要避免的。我设法用
DrawingVisual
解决了这个问题(参见我的答案)。@rashmatash代码没有编译?您所说的为每个项目创建一个路径几何体是什么意思?据我所知,您的原始代码每个项目也只有一个多边形。这段代码的工作原理应该至少与您的原始代码几乎相同(因此我说您可能需要更多的调整)。如果您想使用代码,请考虑绑定背景,并使用某种代码>转换器
,这将更加合乎逻辑。@ RASMATASH,而不是使用<代码>刷< /代码>,尝试添加一些<代码>笔<代码> > <代码>几何图形< /代码>,它将连接<代码> PooToCube < /Code >(每个项目)中的所有点。结果当然应该非常类似于
多边形(我们甚至在这里设置了
IsClosed=“True”
)。
updategolines()
是如何调用的?@VRage:我已经没有代码了,但我相信xaml只是一个
UserControl
,有一个空的
Canvas
,它是
updategolines()
中的
Canvas
变量。然后,每当需要更新画布时,只需清除画布并在事件处理程序中调用
updategolines()
。希望有帮助。