在WPF / MVVM Light中在屏幕上绘制矩形的最有效/最快方法是什么

时间:2018-07-11 23:34:56

标签: c# wpf mvvm mvvm-light

以下代码在2D网格中绘制矩形。一切工作正常,但当它必须绘制超过50,000平方时真的很慢。我知道这听起来很像正方形,但是我用C++/Qt编写了相同的程序,并且速度更快,它几乎立即绘制了50,000个C#/ WPF中的位置,耗时50秒。

在WPF中是否有更好/更快的方法在屏幕上绘制矩形?

XAML

<Window x:Class="DrawingRectanglesWithMvvmLight.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ignore="http://www.galasoft.ch/ignore"
        mc:Ignorable="d ignore"
        Height="319"
        Width="453.333"
        Title="MVVM Light Application"
        DataContext="{Binding Main, Source={StaticResource Locator}}">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid x:Name="LayoutRoot" Margin="0,0,2,0" Height="194" VerticalAlignment="Top" Background="#FF3E7AAC">

        <ItemsControl ItemsSource="{Binding PartsGrid}" Height="200" Margin="5,0,10,-6">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Background="#FFF1F0F0" Margin="10" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle 
                        Width="{Binding Width}" 
                       Height="{Binding Height}" 
                       Margin="{Binding Margin}"
                       Fill="{Binding Fill}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

        <Grid Margin="5,236,6,-69">
            <Button Content="Draw" Command="{Binding DrawCommand}" Margin="328,0,10,0" />
            <Button Content="Reset" Command="{Binding ResetCommand}" Margin="263,0,109,0" />
            <TextBox Text="{Binding Width}" RenderTransformOrigin="1.049,2.023" Margin="124,0,200,0"/>
            <TextBox Text="{Binding Height}" Margin="0,0,334,0"/>
        </Grid>
    </Grid>
</Window>

班级

namespace MvvmLightTEST.Model
{
    public class FSRectangle
    {
        public double Width { get; set; }
        public double Height { get; set; }
        public Thickness Margin { get; set; }
        public Brush Fill { get; set; }
    }
}

ViewModel:

namespace DrawingRectanglesWithMvvmLight.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        public ObservableCollection<FSRectangle> PartsGrid { get; } = new ObservableCollection<FSRectangle>();

        public RelayCommand DrawCommand { get; }
        public RelayCommand ResetCommand { get; }

        public double Width { get; set; }
        public double Height { get; set; }

        public MainViewModel(IDataService dataService)
        {
            DrawCommand = new RelayCommand(Draw);
            ResetCommand = new RelayCommand(Clear);
        }

        private void Draw()
        {
            Clear();

            int xParts = 250;
            int yParts = 200;
            for (int i = 0; i < xParts; i++) {
                for (int j = 0; j < yParts; j++) {
                    FSRectangle part = new FSRectangle();
                    part.Width = Width;
                    part.Height = Height;
                    part.Margin = new Thickness((part.Width + 1) * i, (part.Height + 1) * j, 0, 0);
                    part.Fill = new SolidColorBrush(Color.FromArgb(170, 51, 51, 255));
                    PartsGrid.Add(part);
                }
            }
        }

        private void Clear()
        {
            PartsGrid.Clear();
        }
    }
}

UI

enter image description here

2 个答案:

答案 0 :(得分:3)

由于此用例的性能较慢,因此不使用MVVM。矩形是FrameworkElement,其中包含布局,该功能无法缩放。SO中对此进行了多次讨论。

您可能要考虑

  • 使用DrawingVisualContainerVisual进行低级渲染,而没有布局开销
  • 没有MVVM
  • 提前创建渲染视觉效果,而不是每次渲染

enter image description here

图片courtesy Microsoft,未经允许使用。

MSDN在DrawingVisual

上有此说法
  

DrawingVisual是一个轻量级的绘图类,用于呈现形状,图像或文本。此类被认为是轻量级的,因为它不提供布局或事件处理,从而提高了其运行时性能。因此,绘图是背景和剪贴画的理想选择。 DrawingVisual可用于创建自定义视觉对象。

另请参见

答案 1 :(得分:1)