WPF项目上,需要在Canvas上重复的画图,并将每次的图保存起来。画倒是没什么,但发现过程中窗体一直处于空白状态,直到结束Canvas上才显示内容。网上找了些资料,也还是没搞定,反正大概知道是线程间的交互问题。最后,终于找到了2种解决的办法,写了个例子收集下来,以后反正用的到。例子很简单,也就在主窗体上放一个Canvas和一个Button,点击Button会刷新10次画布。
MainWindow.xaml主界面代码
<Grid>
<Canvas Height="232" HorizontalAlignment="Left" Margin="12,12,0,0" Name="canvas1" VerticalAlignment="Top" Width="467"></Canvas>
<Button Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" Margin="12,265,416,23" />
</Grid>
MainWindow.xaml.cs后台代码
第一种实现
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
if (i % 2 == 0)
{
Ellipse el = new Ellipse();
el.Height = 30;
el.Width = 60;
el.Fill = Brushes.Red;
el.Stroke = Brushes.Black;
canvas1.Children.Add(el);
}
else
{
Ellipse el = new Ellipse();
el.Height = 30;
el.Width = 60;
el.Fill = Brushes.Yellow;
el.Stroke = Brushes.Green;
canvas1.Children.Add(el);
}
System.Threading.Thread.Sleep(1000);
DispatcherHelper.DoEvents();
}
}
}
public static class DispatcherHelper
{
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrames), frame);
try { Dispatcher.PushFrame(frame); }
catch (InvalidOperationException) { }
}
private static object ExitFrames(object frame)
{
((DispatcherFrame)frame).Continue = false;
return null;
}
}
第二种实现
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Thread anotherThread = new Thread(() =>
{
for (int i = 0; i < 10; i++)
{
canvas1.Dispatcher.BeginInvoke((Action)(() =>
{
canvas1.Children.Add(new Ellipse
{
Height = 30,
Width = 60,
Fill = i % 2 == 0 ? Brushes.Red : Brushes.Yellow,
Stroke = i % 2 == 0 ? Brushes.Black : Brushes.Green
});
}));
Thread.Sleep(1000);
}
});
anotherThread.SetApartmentState(ApartmentState.STA);
anotherThread.Start();
}
}