我想编写一个方框图设计工具(类似于Simulink或Modelica)。我已经在C ++ / Qt和C#/ WinForms / GDI +中做过类似的事情,但现在我想去WPF。
取一个块,可以是一个矩形或一个包含其他几个较小形状的正方形作为"输入/输出/双向端口"可能标记或不标记,一些文本,可能是位图或矢量图像。它应该提供上下文菜单,基本鼠标或拖动事件(用于移动块,拉动块之间的连接等),并且应该允许手动重新排列其图形组件,可能在不同的编辑器中。
现在想象一个图表,其中包含1000个这样的块(我夸大了一点以便将来留有足够的空间)和相应的连接。鉴于这个比例,我想知道我是否应该回到WPF的视觉级别并手动建模交互部分,或者是否足以使用图纸,形状甚至控件(就像一个块作为一个按钮)。
当我看到按钮提供的~50种事件类型并将其乘以块数乘以每块的平均端口数时,我有点紧张。许多元素只指向相同的事件处理程序或上下文菜单,因此这些处理程序也可以重定向到管理类。
我仔细阅读了书中的各个WPF章节" Pro C#5.0"而这实际上并没有减轻我的担忧。
那么在这些要求下速度和内存性能方面,建议使用什么级别的WPF(视觉,绘图,形状,控制)?
旁注:我刚刚开始使用WPF,所以我对它的多功能性感到有些震惊。它使我的战略决策变得有点困难,这就是我在全面研究之前提出的要求。
答案 0 :(得分:1)
您可以尝试使用虚拟化创建自定义布局或使用现有布局VirtualizationCanvas。 您需要一个自定义面板,用于将方案项目放置在方案中的正确位置。
此外,您应该创建一个自定义控件,基于具有自定义ItemsControlItems的ItemsControl来处理项目创建等。 然后将您的布局应用于ItemsControl或ListView的ItemPanleTemplate,其中ItemsSource将与带有方案集合的viewModel绑定。
对我而言,这是最简单的选择。
答案 1 :(得分:0)
所以现在我对这个话题做了一个小的可行性研究。向画布添加1800个按钮,分别向它们添加两个鼠标事件,并进一步向窗口添加MouseWheel事件,以允许基本缩放"场景"。我的10年历史的基于英特尔Core2Quad Q6600 + NVidia GTX 460的机器都有观察结果。
应用程序快速启动。 Exe非常小(如预期的那样),8k。调整窗口大小(以查看更多或更少的停靠画布和内容)感觉非常活泼。然而,接近全屏(所有按钮可见)重绘变得有点沉重(如〜5Hz刷新率)。应用程序只需1个按钮即可获取20M内存,而不是10M内存。缩放足够快。此外,在放大时,渲染速度明显加快(因此裁剪等效果很好)。这很好,因为处于紧密放大状态是处理较大图表时最常见的情况。对按钮事件的响应在各个方面都没有受到影响。
结论:使用按钮进行图表显示似乎可行。当图形应用程序针对我的机器的功能进行测量时,它当然不是最理想的,但它仍然足够快。也许使用Shapes代替Buttons可以从中获得更多。但绝对没有回到低级别图形的情况。
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="wpf1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="wpf1"
Width="513"
Height="385"
x:Name="window1"
MouseWheel="window1_MouseWheel">
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" x:Name="canvas1" Background="#FFFFE8E8"/>
</Window>
...和...
public partial class Window1 : Window
{
double totalScale = 1;
public Window1()
{
InitializeComponent();
for (int i=0; i<60; i++)
{
for (int j=0; j<30; j++)
{
Button newButton = new Button();
canvas1.Children.Add(newButton);
newButton.Width = 25;
newButton.Height = 25;
Canvas.SetTop(newButton, j*30);
Canvas.SetLeft(newButton, i*30);
newButton.Click += new System.Windows.RoutedEventHandler(button1_Click);
newButton.MouseMove += new System.Windows.Input.MouseEventHandler(button1_MouseMove);
}
}
}
Button lastButton;
void button1_Click(object sender, RoutedEventArgs e)
{
lastButton = sender as Button;
lastButton.Background = Brushes.Blue;
}
void button1_MouseMove(object sender, MouseEventArgs e)
{
Button butt = sender as Button;
if (lastButton != butt) butt.Background = Brushes.Yellow;
}
void window1_MouseWheel(object sender, MouseWheelEventArgs e)
{
double scaleFactor = Math.Pow(1.0005,e.Delta);
totalScale *= scaleFactor;
canvas1.LayoutTransform = new ScaleTransform(totalScale, totalScale);
}
}