1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        WPF MVVM 彈框之等待框

        共 4127字,需瀏覽 9分鐘

         ·

        2020-10-16 06:19

        WPF?MVVM?彈框之等待框

        目錄

        一、效果

        二、彈框主體改造

        三、等待動畫用戶控件

        四、彈窗 ViewModel 和幫助類的改造

        五、使用方法和代碼地址

        獨(dú)立觀察員 2020年10月13日

        ?

        之前寫過一篇《WPF MVVM 模式下的彈窗》,里面實(shí)現(xiàn)了確認(rèn)框和消息框,經(jīng)過一段時間的演化,目前又新增了可顯示自定義內(nèi)容的彈框、可進(jìn)行信息錄入的彈框、以及本文將要介紹的加載等待框。

        ?

        一、效果

        先來看看效果,首先是其它彈框(動圖):

        43e79e662d01845baf5a63aaa8225677.webp

        ?

        然后是等待彈框(動圖):

        cfb97e4074c4eb948c8c4aef118bb71f.webp

        ?

        下面來看如何實(shí)現(xiàn),當(dāng)然,是在之前的基礎(chǔ)上進(jìn)行的,前一篇文章沒看的話,需要先看一下,或者直接獲取文末提供的代碼查看。

        ?

        二、彈框主體改造

        首先改造的是,給右上角的 X 和底下的確認(rèn)取消按鈕區(qū)域的是否顯示特性 Visibility 綁定了相關(guān)屬性,可以控制是否顯示,這樣在消息框情況下可以隱藏底部按鈕,在等待框情況下可以都隱藏掉。

        68f10f0c174ab046b046beea25f38fab.webp

        ?

        然后是中間的主體區(qū)域,圖上看不出什么變化,實(shí)際上變化還是比較大的,代碼如下:

        f0351e0e3d8ca72b9d408e1531cc153b.webp

        文字版:

        <ScrollViewer Grid.Row="2" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">    <StackPanel Margin="5" VerticalAlignment="Center">        <TextBlock FontSize="16" Text="{Binding DialogMessage, FallbackValue='是否確認(rèn)操作?是否確認(rèn)操作?是否確認(rèn)操作?是否確認(rèn)操作?是否確認(rèn)操作?', TargetNullValue='是否確認(rèn)操作?'}" TextWrapping="Wrap"                   VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="{Binding IsShowText, Converter={StaticResource VisibleConverter}, FallbackValue=Visible}">        TextBlock>
        <ContentControl Visibility="{Binding IsShowCustom, Converter={StaticResource VisibleConverter}, FallbackValue=Collapsed}" Content="{Binding CustomContent}" HorizontalAlignment="{Binding CustomContentHorizontalAlignment, TargetNullValue=Center, Mode=OneWay}" HorizontalContentAlignment="Center" MinWidth="50"> ContentControl> StackPanel>ScrollViewer>


        最外層使用 ScrollViewer 包裹,如果內(nèi)容過多則可滾動。往里一層是 StackPanel,里面有一個 TextBlock 用于顯示文本內(nèi)容,還有一個 ContentControl 用于顯示自定義內(nèi)容(綁定一個 FrameworkElement 類型的對象)。兩種內(nèi)容可以分別控制顯示和隱藏,也可以同時顯示,本文介紹的等待框就是使用了同時顯示。

        ?

        三、等待動畫用戶控件

        按照設(shè)想,等待框的動畫部分作為自定義內(nèi)容放入彈框的 ContentControl 中,所以我們需要新建個用戶控件。(此節(jié)參考朝夕教育 Jovan 老師在 B 站發(fā)布的 WPF 教學(xué)視頻的“動畫實(shí)戰(zhàn)”一節(jié))

        ?

        將一個 Grid 分為四列,每列中放置一個不同顏色的 Border (以 Grid 包裹)并設(shè)置 LayoutTransform 變換類型為 ScaleTransform,并給每個 ScaleTransform 命名:

        4295e38c0f5cbd40c00f80d8dcda0348.webp

        ?

        Border 顯示為圓形并居中的代碼為:

        <Grid.Resources>    <Style TargetType="Border">        <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=ActualWidth, Converter={StaticResource DivideConverter}, ConverterParameter=2}">Setter>        <Setter Property="Height" Value="{Binding RelativeSource={RelativeSource Self}, Path=Width}">Setter>        <Setter Property="CornerRadius" Value="100">Setter>        Style>Grid.Resources>


        也就是設(shè)置寬度為包裹它的 Grid 的寬度的一半,即每列寬度的一半,這個平分的操作是通過轉(zhuǎn)換器 DivideConverter 實(shí)現(xiàn)的,具體可下載代碼查看。然后,高度綁定寬度,這樣就是正方形了。最后再設(shè)置圓角,就成圓形了。注釋的部分是設(shè)置 LayoutTransform 變換的,具體的 ScaleTransform 變換有個 ScaleX 和 ScaleY 值,分別設(shè)置 X 和 Y 方向上的變換數(shù)值(變大為 1.6 倍),由于后面需要對這兩個值設(shè)置動畫,所以此處不能寫死,注釋掉。

        ?

        動畫直接在后臺設(shè)置:

        private void UC_Wait_OnLoaded(object sender, RoutedEventArgs e){    RunAnimation();}
        private void RunAnimation(){ //定義動畫; DoubleAnimation da = new DoubleAnimation() { Duration = new Duration(TimeSpan.FromMilliseconds(1000)), To = 1.6, RepeatBehavior = RepeatBehavior.Forever, AutoReverse = true, };
        Task.Run(async () => { for (int i = 0; i < 4; i++) { Dispatcher.Invoke(() => { var st = FindName($"ST{i + 1}") as ScaleTransform; st?.BeginAnimation(ScaleTransform.ScaleXProperty, da); st?.BeginAnimation(ScaleTransform.ScaleYProperty, da); });
        await Task.Delay(300); } });}

        ?

        界面載入后執(zhí)行動畫方法,動畫方法中先定義了一個 DoubleAnimation 類型的動畫:間隔一秒,目標(biāo)值為 1.6,一直重復(fù),自動反轉(zhuǎn)。然后在循環(huán)中按照命名規(guī)則,依次先使用 FindName 方法找到 ScaleTransform 元素對象,并對其設(shè)置 X 和 Y 方向上的動畫,等待 300 毫秒再設(shè)置下一個,總共四個。

        ?

        四、彈窗?ViewModel 和幫助類的改造

        彈窗 ViewModel 中添加了一個標(biāo)識是否是等待框的屬性 IsWaitDialog,在倒計(jì)時計(jì)時器里面,當(dāng)是等待框時改為正計(jì)時,自然也就不會觸發(fā)關(guān)閉操作,代碼如下:

        /// /// 是否是等待框/// public bool IsWaitDialog { get; set; } = false;
        /// /// 倒計(jì)時計(jì)時器/// /// /// private void Timer_Elapsed(object sender, ElapsedEventArgs e){ if (IsWaitDialog) { LeftTime++; } else { LeftTime--; if (LeftTime <= 0) { _timer.Stop(); CloseCommand.Execute(null); } }}

        ?

        在控制彈框顯示隱藏的屬性 IsShowDialog 的 set 方法中,當(dāng)是等待框時,倒計(jì)時設(shè)為零,方便后面(上面說的)直接進(jìn)行正計(jì)時:

        062a87d04a3dc85caf95bcba935693da.webp

        ?

        關(guān)鍵是幫助方法中,新增一個彈出等待框方法:

        /// /// 彈出等待框/// /// 相關(guān)ViewModel/// 消息內(nèi)容/// 業(yè)務(wù)方法/// 彈窗標(biāo)題/// public static async Task ShowWait(ConfirmBoxViewModel vm, string message, Func action = null, string title = "請耐心等待"){    vm.CustomContent = new UC_Wait();
        await Task.Run(async () => { vm.IsMessageDialog = false; vm.IsWaitDialog = true; vm.IsShowDialog = true; vm.IsShowText = true; vm.IsShowCustom = true; vm.IsShowButton = false; vm.CustomContentHorizontalAlignment = HorizontalAlignment.Stretch.ToString();
        if (!string.IsNullOrWhiteSpace(message)) { vm.DialogMessage = message; }
        if (!string.IsNullOrWhiteSpace(title)) { vm.DialogTitle = title; }
        Console.WriteLine($"等待框就緒,業(yè)務(wù)操作開始執(zhí)行...");
        await Task.Run(async () => { await action?.Invoke();
        }).ContinueWith(_ => { vm.IsShowDialog = false; Console.WriteLine($"業(yè)務(wù)操作執(zhí)行完畢,等待框關(guān)閉."); }); });}

        ?

        先將自定義內(nèi)容設(shè)置為等待動畫用戶控件,接下來是一些顯示方面的設(shè)置。

        關(guān)鍵是如何在執(zhí)行完業(yè)務(wù)方法后才關(guān)閉彈窗呢?

        一開始 Func action 這個參數(shù)我用的還是 Action action,這樣的話,action?.Invoke() 這里不能 await,然后 .NET Core 3.1 又不支持 action?.BeginInvoke(callback, null) 這種寫法。

        后來把參數(shù)類型改為 Func ,就可以 await action?.Invoke() 了,而且神奇的是,調(diào)用的地方不用修改(后面展示)。這樣的話,就可以通過如下方式(ContinueWith)達(dá)到業(yè)務(wù)方法執(zhí)行完成之后關(guān)閉彈窗了:

        Console.WriteLine($"等待框就緒,業(yè)務(wù)操作開始執(zhí)行...");
        await Task.Run(async () =>{ await action?.Invoke();
        }).ContinueWith(_ =>{ vm.IsShowDialog = false; Console.WriteLine($"業(yè)務(wù)操作執(zhí)行完畢,等待框關(guān)閉.");});

        ?

        五、使用方法和代碼地址

        使用就比較簡單了:

        WaitCommand ??= new RelayCommand(o => true, async o =>{    await ConfirmBoxHelper.ShowWait(DialogVm, "正在執(zhí)行業(yè)務(wù)操作...", async () =>    {        await Task.Delay(1000 * 10);        Console.WriteLine("操作完成");    });});

        ?

        代碼地址:https://gitee.com/dlgcy/WPFTemplate

        9dd58c3a3e59c0c98b31fb32c003d0dd.webp


        資源分享


        謝謝您的支持,需要任何資源,只需要在公眾號后臺回復(fù)對應(yīng)數(shù)字即可:

        01:dotnet
        02:java
        03:android
        04:C++
        05:qt
        06:react

        沒有的資源或資源鏈接失效,請給我留言或加我微信。
        另:大部分資源可在我的網(wǎng)站搜索哦:https://dotnet9.com

        瀏覽 54
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            黄色电影免费看 | 天天弄综合 | 国产精品一卡二卡在线观看 | 色噜噜人妻丝袜aV先锋影音先 | 香港三日三级少妇三级66 | 青娱乐最新网站 | 娇妻被老外性调教18 | 操逼四区| 国产精品小视频网站 | 美女一级片 |