WPF 自定義等待對話方塊、多執行緒等待的問題
阿新 • • 發佈:2019-02-20
從網上找個等待對話方塊的程式例項,找了好幾次依然不怎麼滿意。於是自己寫一個好了。並且封裝一下。
目前僅適用於WPF。winform的可以稍微改一下也行
不說廢話了。
一、等待對話方塊介面設計
<span style="font-size:14px;color:#333333;"><Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="DialogEx.Controls.WaittingDlg" Title="WaittingDlg" Height="45" Width="150" WindowStyle="None" AllowsTransparency="True" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded"> <Grid> <Border x:Name="bDlgBorder" Grid.ColumnSpan="2" BorderThickness="1" CornerRadius="3"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="35"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid Width="35" Height="35" Grid.Column="0" HorizontalAlignment="Left"> <Grid.Resources> <DrawingBrush x:Key="brush" Stretch="None" AlignmentX="Center" AlignmentY="Top"> <DrawingBrush.Drawing> <GeometryDrawing x:Name="bBrushColor" Brush="Red"> <GeometryDrawing.Geometry> <EllipseGeometry RadiusX="2" RadiusY="5"/> </GeometryDrawing.Geometry> </GeometryDrawing> </DrawingBrush.Drawing> </DrawingBrush> </Grid.Resources> <Grid.Triggers> <EventTrigger RoutedEvent="FrameworkElement.Loaded"> <BeginStoryboard> <Storyboard RepeatBehavior="Forever"> <DoubleAnimation Storyboard.TargetName="r01" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.00000" To="0"/> <DoubleAnimation Storyboard.TargetName="r02" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.08333" To="0"/> <DoubleAnimation Storyboard.TargetName="r03" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.16666" To="0"/> <DoubleAnimation Storyboard.TargetName="r04" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.24999" To="0"/> <DoubleAnimation Storyboard.TargetName="r05" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.33332" To="0"/> <DoubleAnimation Storyboard.TargetName="r06" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.41665" To="0"/> <DoubleAnimation Storyboard.TargetName="r07" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.49998" To="0"/> <DoubleAnimation Storyboard.TargetName="r08" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.58331" To="0"/> <DoubleAnimation Storyboard.TargetName="r09" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.66664" To="0"/> <DoubleAnimation Storyboard.TargetName="r10" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.74997" To="0"/> <DoubleAnimation Storyboard.TargetName="r11" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.83330" To="0"/> <DoubleAnimation Storyboard.TargetName="r12" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08333" BeginTime="0:0:0.91663" To="0"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Grid.Triggers> <Rectangle x:Name="r01" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="0"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r02" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="30"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r03" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="60"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r04" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="90"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r05" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="120"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r06" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="150"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r07" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="180"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r08" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="210"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r09" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="240"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r10" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="270"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r11" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="300"/> </Rectangle.RenderTransform> </Rectangle> <Rectangle x:Name="r12" Fill="{StaticResource brush}" Opacity="0.2" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="330"/> </Rectangle.RenderTransform> </Rectangle> </Grid> <TextBlock Grid.Column="1" x:Name="txtWaittingInfo" Margin="5,2,0,0" TextWrapping="Wrap"/> </Grid> </Border> </Grid> </Window></span><span style="color:#ff0000;font-size:14px;"> </span>
二、等待對話方塊後臺處理 - 還是典型的事件加控制元件。。。。沒時間整也沒必要分層
<span style="font-size:14px;">using System; using System.Linq; using System.Text; using System.Windows; using System.Threading; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; using System.Collections.Generic; using System.Windows.Media.Imaging; using System.Runtime.InteropServices; namespace DialogEx.Controls { /// <summary> /// WaittingDlg.xaml 的互動邏輯 /// </summary> public partial class WaittingDlg : Window { [DllImport("user32.dll")] static extern bool EnableWindow(IntPtr hWnd, bool bEnable); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetForegroundWindow(IntPtr hWnd); //建構函式 public WaittingDlg(string sWaittingInfo = "", string sWindowColor = "", string sDlgBorderColor = "", int nBorderWidth = 5,int nWidth = 0,int nHeight = 0) { InitializeComponent(); if (nWidth != 0) { this.Width = nWidth; } if (nHeight != 0) { this.Height = nHeight; } this.sWaittingInfo = "請等待。。。"; //提示資訊 this.sWindowColor = "White"; //視窗顏色 this.sDlgBorderColor = "#FF5B9BD1"; //邊框顏色 this.nBorderWidth = 5; //邊框寬度 if (sWaittingInfo != "") { this.sWaittingInfo = sWaittingInfo; } if (sWindowColor != "") { this.sWindowColor = sWindowColor; } if (sDlgBorderColor != "") { this.sDlgBorderColor = sDlgBorderColor; } if (nBorderWidth > 0) { this.nBorderWidth = nBorderWidth; } this.Closing += new System.ComponentModel.CancelEventHandler(Window1_Closing); } //關閉事件 void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e) { this.Closing -= new System.ComponentModel.CancelEventHandler(Window1_Closing); IntPtr handle = (new System.Windows.Interop.WindowInteropHelper(this)).Handle; IntPtr ownerhandle = (new System.Windows.Interop.WindowInteropHelper(this.Owner)).Handle; EnableWindow(handle, false); EnableWindow(ownerhandle, true); } //初始化完成 private void Window_Loaded(object sender, RoutedEventArgs e) { IntPtr handle = (new System.Windows.Interop.WindowInteropHelper(this)).Handle; EnableWindow(handle, true); SetForegroundWindow(handle); this.AutoChangeSize(); } //等待提示資訊 public string sWaittingInfo { set { txtWaittingInfo.Text = value; } get { return txtWaittingInfo.Text.ToString().Trim(); } } //視窗背景 Img public string sWindowBkImg { set { Uri uri = new Uri(value, UriKind.RelativeOrAbsolute); BitmapImage bimg = new BitmapImage(uri); this.Background = new ImageBrush(bimg); } } //視窗背景顏色 String public string sWindowColor { /***********用法******* * sWindowColor = "Red"; *********************/ set { this.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value)); } } //視窗背景顏色 Color public Color cWindowColor { /***********用法******* * cWindowColor = System.Windows.Media.Colors.Red; *********************/ set { bDlgBorder.BorderBrush = new SolidColorBrush(value); } } //邊框顏色 String public string sDlgBorderColor { /***********用法******* * sDlgBorderColor = "Red"; *********************/ set { bDlgBorder.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value)); } } //邊框顏色 Color public Color cDlgBorderColor { /***********用法******* * cDlgBorderColor = System.Windows.Media.Colors.Red; *********************/ set { bDlgBorder.BorderBrush = new SolidColorBrush(value); } } //邊框寬度 public int nBorderWidth { set { bDlgBorder.BorderThickness = new Thickness(value); } } //自動調整文字上下居中 private void AutoChangeSize() { if (this.txtWaittingInfo.ActualHeight + 8 > this.ActualHeight) { this.txtWaittingInfo.SetValue(VerticalAlignmentProperty, VerticalAlignment.Top); this.txtWaittingInfo.Margin = new Thickness(0, 2, 0, 0); } else { this.txtWaittingInfo.SetValue(VerticalAlignmentProperty,VerticalAlignment.Center); } } } } </span>
三、等待對話方塊 Helper,這是封裝好的呼叫方法而已。怎麼呼叫再第四步
<span style="font-size:14px;color:#333333;">using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Windows; using System.Windows.Interop; namespace DialogEx.Controls.ProcessWindow { public class WaittingDlgHelper { /// <summary> /// 等待關閉時的回撥 /// </summary> public delegate void CloseWaitDialogCallBack(); [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLong(IntPtr hwnd, int index); [DllImport("user32.dll")] private static extern bool EnableWindow(IntPtr hWnd, bool bEnable); private static WaittingDlg _WatitDlg; private static CloseWaitDialogCallBack _CallBack; /// <summary> /// 是否已啟用等待對話方塊 /// - 呼叫本Helper內部函式時不需要對此判斷 /// - 僅對外部顯示是否正在等待 /// </summary> public static bool IsWaitAlive { get { return _WatitDlg != null; } } /// <summary> /// 顯示等待對話方塊 /// </summary> /// <param name="win"></param> /// <param name="sWaittingInfo"></param> /// <param name="sWindowColor"></param> /// <param name="sDlgBorderColor"></param> /// <param name="nBorderWidth"></param> /// <param name="nWidth"></param> /// <param name="nHeight"></param> public static void ShowWaitDialog(Window win, string sWaittingInfo = "", string sWindowColor = "", string sDlgBorderColor = "", int nBorderWidth = 5, int nWidth = 0, int nHeight = 0) { win.Dispatcher.Invoke(new Action(() => { if (_WatitDlg != null) { _WatitDlg.Close(); _WatitDlg = null; } IntPtr handle = (new System.Windows.Interop.WindowInteropHelper(win)).Handle; _WatitDlg = new WaittingDlg(sWaittingInfo, sWindowColor, sDlgBorderColor, nBorderWidth, nWidth, nHeight); _WatitDlg.Owner = win; _WatitDlg.WindowStartupLocation = WindowStartupLocation.CenterOwner; _WatitDlg.ShowInTaskbar = false; WindowInteropHelper helper = new WindowInteropHelper(_WatitDlg); EnableWindow(handle, false); _WatitDlg.ShowDialog(); })); } /// <summary> /// 關閉等待對話方塊 /// </summary> /// <param name="win"></param> public static void CloseWaitDialog(Window win) { win.Dispatcher.Invoke(new Action(() => { if (_WatitDlg != null) { _WatitDlg.Close(); _WatitDlg = null; } if (_CallBack != null) { _CallBack(); } })); } /// <summary> /// 設定對話方塊內容 /// </summary> /// <param name="win"></param> /// <param name="strTitle"></param> public static void SetWaitDialogTitle(Window win, string strTitle = "") { win.Dispatcher.Invoke(new Action(() => { if (_WatitDlg != null) { if (strTitle != "") { _WatitDlg.sWaittingInfo = strTitle; } } })); } /// <summary> /// 設定關閉等待對話方塊回撥 - 收到關閉通知即回撥 /// </summary> public static void SetWaitDialogCloseCallBack(CloseWaitDialogCallBack CallBackMethod) { _CallBack += CallBackMethod; } } }</span><span style="color:#ff0000;"> </span>
四、 關於如何使用等待對話方塊 - 你必須懂得後臺執行緒,或者執行緒。 本次僅以後臺執行緒為例
<pre name="code" class="csharp"> <span style="font-size:14px;color:#333333;">//啟動等待
private void OpenWaittingDialog_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker backWork = new BackgroundWorker()
{
WorkerReportsProgress = false,
WorkerSupportsCancellation = true
};
backWork.DoWork += backWork_DoWork;
backWork.RunWorkerCompleted += backWork_RunWorkerCompleted;
backWork.RunWorkerAsync();
WaittingDlgHelper.ShowWaitDialog(this,"請等待。。。");
}
//關閉等待
private void CloseWaittingDialog_Click(object sender, RoutedEventArgs e)
{
WaittingDlgHelper.CloseWaitDialog(this);
}
//正在執行
void backWork_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(8000);
}
//執行完
void backWork_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBoxEx.Show(this, "提示", "等待完成",MessageBoxExButton.Ok,MessageBoxExImage.Information);
WaittingDlgHelper.CloseWaitDialog(this);
}</span>
五、關於等待對話方塊的回撥事件 。 暫時以委託實現。可以用事件。。但是差別不大。。也沒什麼實際卵用
<span style="white-space:pre"> </span><span style="font-size:14px;color:#333333;">//註冊等待對話方塊關閉通知事件
<span style="white-space:pre"> </span>WaittingDlgHelper.SetWaitDialogCloseCallBack(this.WaittCloseCallBack);
<span style="white-space:pre"> </span>//等待關閉回撥
public void WaittCloseCallBack()
{
//你要在等待對話方塊關閉時執行的操作
}</span>