【问题标题】:What is the most efficient/fastest way to draw rectangles on the screen in WPF / MVVM Light在WPF / MVVM Light中在屏幕上绘制矩形的最有效/最快的方法是什么
【发布时间】:2018-07-11 23:34:55
【问题描述】:

以下代码在二维网格中绘制矩形。一切都很好,只是当它必须绘制超过 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; }
    }
}

视图模型:

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();
        }
    }
}

用户界面

【问题讨论】:

标签: c# wpf mvvm mvvm-light


【解决方案1】:

由于此用例的性能较慢,因此不使用 MVVM。矩形是FrameworkElements,其中包含布局,这是一个不缩放的功能,这在 SO 中讨论了很多次。

你可以考虑

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

图片courtesy微软,未经许可使用。

MSDN 在DrawingVisual 上有这个说法

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

另见

【讨论】:

  • 我尝试直接在代码隐藏中绘制Rectangle()s,并且仅通过删除 MVVM 性能提高了很多。我想我将不得不在不使用 MVVM 的情况下绘制矩形。我还将研究“DrawingVisual”和“ContainerVisual”。您能否详细说明您的第三个建议? create render visuals ahead of time rather than per render 谢谢。
  • 如果您要绘制的东西是静态的(或者即使您打算移动它们但数量保持不变),则在创建窗口时分配它们并将它们存储在一个字段中,而不是在渲染期间。这将提高性能
  • 尺寸和数量将是动态的。谢谢!
【解决方案2】:

【讨论】:

  • 我不认为我可以绑定到Rect(),所以我不需要使用 MVVM。我会在不使用 MVVM 的情况下尝试一下,看看它的效率如何。谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
  • 2011-01-24
  • 1970-01-01
  • 2012-06-02
  • 2013-12-10
  • 1970-01-01
  • 2011-12-19
相关资源
最近更新 更多