zip's

while(true) { Write it down; Think about it; Refine it; Sleep(); }

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

当程序在进行一项耗时的工作时,加上一个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
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://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>

 

线程窗口Code Behind
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();
}
}

 

posted on 2010-12-23 11:20  zip's  阅读(1034)  评论(0编辑  收藏  举报