WPF / MVVM Light中最efficient/fastest在屏幕上绘制矩形的方法是什么
What is the most efficient/fastest way to draw rectangles on the screen in WPF / MVVM Light
以下代码在二维网格中绘制矩形。一切工作正常,只是当它必须绘制超过 50,000 个正方形时它真的很慢。我知道这听起来像很多方块,但我用 C++/Qt
编写了相同的程序,而且速度快得多,它几乎可以立即绘制 50,000,而在 C#/WPF 中需要 50 秒。
有没有 better/faster 在 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>
Class:
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
带有 RectangleGeometry 的路径是一个选项:
https://docs.microsoft.com/en-us/dotnet/framework/wpf/graphics-multimedia/how-to-define-a-rectangle-using-a-rectanglegeometry
由于此用例的性能低下,未使用 MVVM。矩形是包含布局的 FrameworkElement
s,这是一种不缩放的功能 这在 SO 中讨论了很多次。
您可能需要考虑
- 使用
DrawingVisual
和 ContainerVisual
进行较低级别的渲染,没有布局开销
- 没有 MVVM
- 提前创建渲染视觉效果而不是每次渲染
图片courtesy微软,未经许可使用。
MSDN 在 DrawingVisual
上有此说法
The DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout or event handling, which improves its runtime performance. For this reason, drawings are ideal for backgrounds and clip art. The DrawingVisual can be used to create a custom visual object.
另见
以下代码在二维网格中绘制矩形。一切工作正常,只是当它必须绘制超过 50,000 个正方形时它真的很慢。我知道这听起来像很多方块,但我用 C++/Qt
编写了相同的程序,而且速度快得多,它几乎可以立即绘制 50,000,而在 C#/WPF 中需要 50 秒。
有没有 better/faster 在 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>
Class:
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
带有 RectangleGeometry 的路径是一个选项: https://docs.microsoft.com/en-us/dotnet/framework/wpf/graphics-multimedia/how-to-define-a-rectangle-using-a-rectanglegeometry
由于此用例的性能低下,未使用 MVVM。矩形是包含布局的 FrameworkElement
s,这是一种不缩放的功能 这在 SO 中讨论了很多次。
您可能需要考虑
- 使用
DrawingVisual
和ContainerVisual
进行较低级别的渲染,没有布局开销 - 没有 MVVM
- 提前创建渲染视觉效果而不是每次渲染
图片courtesy微软,未经许可使用。
MSDN 在 DrawingVisual
The DrawingVisual is a lightweight drawing class that is used to render shapes, images, or text. This class is considered lightweight because it does not provide layout or event handling, which improves its runtime performance. For this reason, drawings are ideal for backgrounds and clip art. The DrawingVisual can be used to create a custom visual object.