用WPF實現“等待”小轉盤


我們在開發過程中常常會遇到一些比較耗時的操作,比如一次較慢的網絡訪問,或者復制一個較大的文件等,如果不使用多線程,而是直接用UI線程去做這些動作,那么就會讓用戶界面失去響應,帶來很不好的用戶體驗。較好的做法是在界面上呈現出一個小動畫,用戶看到有東西在動,就不認為程序已經死掉,例如這個:

 當然了,更好的做法是實現一個進度條,但很多時候我們根本不能獲取到進度,所以只能顯示這么一個小轉盤,小轉盤效果的比較簡單的實現方法是顯示一個小小的gif,但WPF默認的Image控件並不直接支持gif動畫效果,所幸的是我們可以通過一個叫“WpfAnimatedGif”第三方的庫來很方便地把這個動畫效果顯示出來,這個庫可以通過NuGet獲取到,我提供的完整代碼下載里也有。這是我的Demo的效果圖:

小轉盤出現的同時,我們希望能夠暫時阻擋用戶的操作,我最早想到的辦法是把窗口Disable掉,也就是把它的IsEnabled屬性設為False,但這樣做可能達不到我們想要的效果,因為這樣只能把窗口的客戶區Disabled掉,而非客戶區卻仍然可以操作,比如標題欄上的最小化,最大化和關閉按鈕,所以比較好的做法是用一個模態對話框。這是我設計的模態對話框:

<Window x:Class="WaitingDemo.WaitingDlg"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:gif="http://wpfanimatedgif.codeplex.com"
        Title="WaitingDlg" Height="100" Width="400" WindowStyle="None" Background="Transparent" AllowsTransparency="True"
        WindowStartupLocation="CenterOwner" Closing="Window_Closing" Loaded="Window_Loaded"
        TextOptions.TextFormattingMode="Display">
    <Grid>
        <Border CornerRadius="5" Height="40" BorderBrush="Black" BorderThickness="1" Background="White" Width="350">
            <Border.Effect>
                <DropShadowEffect Color="Black"></DropShadowEffect>
            </Border.Effect>
            <Grid VerticalAlignment="Center">
                <Image gif:ImageBehavior.AnimatedSource="loading.gif" Width="28" Height="28" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5,0,0,0"/>
                <TextBlock Name="tbPrompt" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.ColumnSpan="2" Margin="0,7">任務執行中...</TextBlock>
            </Grid>
        </Border>
    </Grid>
</Window>

這是幾個要注意的屬性設置:

  • WindowStyle - 設置為None來使得這個模態對話框沒有標題欄,當然也就沒有了最小化、最大化和關閉按鈕
  • Background - 設置為Transparent來讓這個模態對話框背景透明
  • AllowsTransparency - 如果不把這個屬性設置為True,那模態對話框的依然是不透明的,你將看到一個黑框
  • WindowStartupLocation - 設置為CenterOwner讓模態對話框默認居中顯示

細心的你也許還發覺了:只是不顯示關閉按鈕還是不夠的,用戶還是可以通過<Alt>+<F4>來關閉這個對話框,所以需要處理Closing事件,判斷這個關閉動作是否我們的程序提出來的。

對於處理任務,我創建了一個接口:

    public interface ILongTimeTask
    {
        void Start(WaitingDlg dlg);
    }

將WaitingDlg傳入的原因是想讓工作線程結束的時候關閉掉這個模態對話框:

        public void TaskEnd(Object result)
        {
            m_taskResult = result; //用於返回執行的結果(也可以為null)
            m_bCloseByMe = true; //這個標志表示“關閉”動作由我們的程序提出
            Dispatcher.BeginInvoke(new CloseMethod(Close)); //工作線程對界面元素的操作必須用這種調用方式
        }

完整代碼:下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM