轉帖|其它|編輯:郝浩|2011-06-09 14:28:26.000|閱讀 565 次
概述:當程序在進行一項耗時的工作時,加上一個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@fc6vip.cn
文章轉載自:博客園