【发布时间】:2013-03-24 12:20:14
【问题描述】:
如果单击按钮,我有一个大约需要 5 秒才能完成的功能。如果单击按钮,我想显示某种通知以指示正在处理按钮单击,例如
<Button Click="OnButtonClick" Content="Process Input" />
<Border x:Name="NotificationBorder" Opacity="0" IsHitTestVisible="False"
Width="500" Height="100" Background="White">
<TextBlock Text="Your input is being processed" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
然后在按钮上的代码隐藏中单击:
private void OnButtonClick(Object sender, RoutedEventArgs e)
{
DoubleAnimation da = new DoubleAnimation
{
From = 5,
To = 0,
Duration = TimeSpan.FromSeconds(2.5),
};
// Making border visible in hopes that it's drawn before animation kicks in
NotificationBorder.Opacity = 1;
da.Completed += (o, args) => NotificationBorder.Opacity = 0;
NotificationBorder.UpdateLayout(); //Doesn't do anything
UpdateLayout(); // Doesn't do anything
NotificationBorder.BeginAnimation(OpacityProperty, da);
// Simulate calculationheavy functioncall
Thread.Sleep(5000);
}
不知何故,UpdateLayout() 的渲染速度不够快,只有在 Thread.Sleep 的 5 秒结束后才会显示通知。
Dispatcher.Invoke((Action)(() => NotificationBorder.Opacity = 1), DispatcherPriority.Render); 也不起作用。
此外,我不能让Thread.Sleep 在单独的工作线程中运行 - 在实际应用程序中,它需要从 Dispatcher 拥有的对象中读取数据并(重新)构建部分 UI。
有没有办法在调用Thread.Sleep() 之前使其可见?
【问题讨论】:
-
你试过 Dispatcher.BeginInvoke((Action)(() => Thread.Sleep(5000)) 吗?
-
您没有看到更新,因为您的模拟正在休眠 UI 线程。如果您的长时间运行的进程也在主线程中,您将看到相同的行为。
-
您需要在单独的线程中异步执行长时间运行的函数。您可以使用BackgroundWorker 来执行此任务。
-
为什么要将
NotificationBorder的不透明度从 5 设置为 0?不透明度是一个介于 0 和 1 之间的值。 -
@Clemens:这样不透明度是可见的,并且仅在动画的最后 20% 中淡出(我没有费心寻找“更好”的替代方案,如果有的话?)。
BackgroundWorker可以访问 Dispatcher 拥有的对象吗? IE。从数据网格中恢复项目?