彩票走势图

在单独的UI线程中不断更新主线程的工作状态

转帖|其它|编辑:郝浩|2011-06-09 14:28:26.000|阅读 552 次

概述:当程序在进行一项耗时的工作时,加上一个UI显示当前的进度,这样可以避免让用户等到不耐烦,客户可能以为死机了,可能狂点鼠标,造成更差的效率问题。对于这个问题,解决方法有多种:

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

  当程序在进行一项耗时的工作时,加上一个UI显示当前的进度,这样可以避免让用户等到不耐烦,客户可能以为死机了,可能狂点鼠标,造成更差的效率问题。对于这个问题,解决方法有多种:

  1,都在主线程中进行,将耗时任务分解成小块,主线程处理,同时更新GUI,MSDN中有个很好的例子 "A Single-Threaded Application with a Long-Running Calculation";

  2,工作线程为非GUI线程,负责处理耗时工作,主线程更新GUI。这种方法只有一个GUI线程,对多线程编程,这个是通常的选择;

  3,主线程,工作线程都是UI线程,主线程处理耗时工作,工作线程负责处理UI更新提示。某些情况下,不得不这么做。这里详细介绍一个实现。

namespace Program
{
     public class WaitPromptArgs
     {
         public bool ShowInCenterOfScreen { get; set; }
         public double Left { get; set; }
         public double Top { get; set; }

         public string Status { get; set; }
     }

     public class WaitPrompt
     {
         private bool working = false;

         private readonly Window ParentWnd = null;
         public WaitPrompt(Window owner)
         {
             ParentWnd = owner;
         }

  private readonly ManualResetEvent BeginComplete =
 new ManualResetEvent(false);
         public void BeginWait()
         {
             try
             {
                 BeginComplete.Reset();
                 working = true;

                 // calc startup position
                 WaitPromptArgs args = new WaitPromptArgs();
                 if (ParentWnd == null)
                 {
                     args.ShowInCenterOfScreen = true;
                 }
                 else
                 {
                     // change cursor to hourglass
                     ParentWnd.Cursor = Cursors.Wait;

                     args.ShowInCenterOfScreen = false;
                     args.Left = ParentWnd.Left + 4;
                     args.Top = ParentWnd.Top + 32;
                 }
                 args.Status = string.Empty;

                 // start a new thread
                 t = new Thread(new ParameterizedThreadStart(OnThreadStart));
                 t.SetApartmentState(ApartmentState.STA);
                 t.IsBackground = true;
                 t.Start(args);

                 BeginComplete.WaitOne(); // wait untill process start complete
             }
             catch (Exception e)
             {
                 throw new Exception( "wait prompt window", e);
             }
         }

         private Thread t = null;
         private Dispatcher theDispatcher = null;
         private DispatcherFrame theFrame = null;
         private WaitingWnd w = null;

         private void OnThreadStart(object obj)
         {
             try
             {
                 WaitPromptArgs args = obj as WaitPromptArgs;
                 w = new WaitingWnd();
                 if (args.ShowInCenterOfScreen)
                 {
                     w.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                 }
                 else
                 {
                     w.WindowStartupLocation = WindowStartupLocation.Manual;
                     w.Left = args.Left;
                     w.Top = args.Top;
                 }
                 w.Show();

                 theFrame = new DispatcherFrame();
                 theDispatcher = Dispatcher.CurrentDispatcher;

                 BeginComplete.Set(); // start complete, notify other threads

                 theDispatcher.BeginInvoke(DispatcherPriority.Background, 
new DispatcherOperationCallback(UpdateDescription), args.Status);
                 Dispatcher.PushFrame(theFrame);

                 w.Close();
                 w = null;
             }
             catch (ThreadAbortException)
             {
                 Thread.ResetAbort();
             }
             finally
             {
                 CleanUp();
             }
         }

         //
 you can NOT directly set this string, because the other thread holds the window
         // so, have to delegate by the other thread dispatcher object
         public void UpdateHint(string hint)
         {
             if (working)
             {
                 // w.Description = hint;
                 theDispatcher.BeginInvoke(DispatcherPriority.Background, 
new DispatcherOperationCallback(UpdateDescription), hint);
             }
         }
         private object UpdateDescription(object des)
         {
             w.Description = des as string;
             return null;
         }

         public void EndWait()
         {
             try
             {
                 theDispatcher.BeginInvoke(DispatcherPriority.Normal, 
new DispatcherOperationCallback(ExitFrames), theFrame);
             }
             catch (Exception e)
             {
                 throw new Exception( "wait prompt window", e);
             }
             finally
             {
                 if (ParentWnd != null)
                     ParentWnd.Cursor = Cursors.Arrow;

                 working = false;
             }
         }
         private object ExitFrames(object f)
         {
             ((DispatcherFrame)f).Continue = false;
             return null;
         }
         private void CleanUp()
         {
             try
             {
                 if (w != null)
                     w.Close();
 
                 Debug.Assert(t != null  && theDispatcher != null && theFrame != null);

                 t = null;
                 theDispatcher = null;
                 theFrame = null;
                 w = null;
             }
             catch (Exception e)
             {
                 throw new Exception( "wait prompt window", e);
             }
         }
     }
}

 

<Window
     x:Class="Program.WaitingWnd"
     xmlns= "//schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x= "//schemas.microsoft.com/winfx/2006/xaml"
     Title= "Please wait ..." Height="100" Width="380" ResizeMode="NoResize"
     Background= "{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
     WindowStyle= "ToolWindow" WindowStartupLocation="Manual"
     >
     <Grid>
         <Grid.RowDefinitions>
             <RowDefinition Height="32"/>
             <RowDefinition Height="*"/>
         </Grid.RowDefinitions>
         <TextBlock x:Name="_description" HorizontalAlignment="Left" 
VerticalAlignment="Center" Text="TextBlock"
 TextWrapping="Wrap" Margin="10,0,0,0"/>
         <ProgressBar HorizontalAlignment=
"Stretch" VerticalAlignment="Center" 
Width="Auto" Height="15" Grid.Row="1" 
Margin="10,0,10,0" IsIndeterminate="True"/>
     </Grid>
</Window> namespace Program
{
     ///  <summary>
     /// Interaction logic for WaitingWnd.xaml
     ///  </summary>
     public partial class WaitingWnd : Window
     {
         public string Description { set { _description.Text = value; } }

         public WaitingWnd()
         {
             InitializeComponent();
         }
     }
}

public partial class Window1 : Window
{
     readonly WaitPrompt wp = null;
     public Window1()
     {
         InitializeComponent();

         wp = new WaitPrompt(this);
     }

    
     private void Begin_Click(object sender, RoutedEventArgs e)
     {
         wp.BeginWait();
         wp.UpdateHint( "hello world!");
     }

     private void Send_Click(object sender, RoutedEventArgs e)
     {
         wp.UpdateHint(theWords.Text);
     }

     private void End_Click(object sender, RoutedEventArgs e)
     {
         wp.EndWait();
     }
}


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:博客园

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP