首页 新闻 会员 周边 捐助

关于wpf里面的显示与影藏

0
[待解决问题]

wpf里面我想用wpfanimatedgif组件显示一个gif,但是因为要等到OnClick的方法执行完才会显示,所以我采用异步的方式去解决,但是貌似添加为异步之后,那个gif就不现实了,但是用同步的方法又打不到效果。

灬丶的主页 灬丶 | 初学一级 | 园豆:9
提问于:2021-07-02 09:44
< >
分享
所有回答(2)
0

你试试这样写

private async void btnOn_Click(object sender, RoutedEventArgs e)
{
    IISStateWaiting.Visibility = Visibility.Visible;
    IISStateFailure.Visibility = Visibility.Hidden;
    await Task.Run(()=>{}); // 耗时操作
    IISStateWaiting.Visibility = Visibility.Hidden;
    IISStateFailure.Visibility = Visibility.Visible;
}
拓拓 | 园豆:1055 (小虾三级) | 2021-07-02 10:03

应该不可以,因为wpf里面必须等到btnOn_Click整个方法执行完才会有效, await就阻塞了btnOn_Click这个方法

支持(0) 反对(0) 灬丶 | 园豆:9 (初学一级) | 2021-07-02 10:06

@灬丶: await 的时候就直接返回了,等你代码执行完毕之后再回来继续

支持(0) 反对(0) 拓拓 | 园豆:1055 (小虾三级) | 2021-07-02 10:11

@拓拓: 但是Task.Factory.StartNew也差不多的吧,并且.net4.0没有async await

支持(0) 反对(0) 灬丶 | 园豆:9 (初学一级) | 2021-07-02 10:14
0

首先应该避免在OnClick事件处理函数中去做任何耗时操作,这是UI线程,UI线程的时间片是很昂贵的,尽可能去做渲染的工作。在UI线程执行耗时操作会严重影响界面的渲染,导致无响应,你说的gif应该是指的忙指示器,肯定也没法渲染。

这样的场景在我们做过的系统中非常普遍,于是封装了一些好用的扩展方法,最常用的是异步线程执行耗时操作并显示忙指示器,异步执行完毕再切换回UI线程执行界面刷新。

using System;
using System.Threading.Tasks;

namespace Frontier.Wif.Utilities.Extensions
{
    /// <summary>
    /// Defines the <see cref="TaskExtensions" />
    /// </summary>
    public static class TaskExtensions
    {
        #region Methods

        /// <summary>
        /// 延时异步执行方法。
        /// </summary>
        /// <param name="action">待执行方法</param>
        /// <param name="delayTime">延时时间(毫秒)</param>
        public static void DelayRun(this Action action, int delayTime)
        {
            Task.Delay(delayTime).ContinueWith(unusedTask => action());
        }

        /// <summary>
        /// The Run
        /// </summary>
        /// <param name="workAction">The action<see cref="Action"/></param>
        /// <param name="completedAction">The completedAction<see cref="Action"/></param>
        /// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
        /// <returns>The <see cref="Task"/></returns>
        public static Task RunAsync(this Action workAction, Action completedAction,
                bool runCompletedActionInUIThread = true)
        {
            var taskScheduler = runCompletedActionInUIThread
                    ? TaskScheduler.FromCurrentSynchronizationContext()
                    : TaskScheduler.Current;

            return Task.Run(workAction).ContinueWith(unusedTask => completedAction(), taskScheduler);
        }

        /// <summary>
        /// The Run
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="workAction">The action<see cref="Action"/></param>
        /// <param name="completedFunction">The completedFunction<see cref="Func{TResult}"/></param>
        /// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
        /// <returns>The <see cref="Task{TResult}"/></returns>
        public static Task<TResult> RunAsync<TResult>(this Action workAction, Func<TResult> completedFunction,
                bool runCompletedActionInUIThread = true)
        {
            var taskScheduler = runCompletedActionInUIThread
                    ? TaskScheduler.FromCurrentSynchronizationContext()
                    : TaskScheduler.Current;

            return Task.Run(workAction).ContinueWith(unusedTask => completedFunction(), taskScheduler);
        }

        /// <summary>
        /// The Run
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="workFunction">The function<see cref="Func{TResult}"/></param>
        /// <param name="completedAction">The completedAction<see cref="Action"/></param>
        /// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
        /// <returns>The <see cref="Task{TResult}"/></returns>
        public static Task<TResult> RunAsync<TResult>(this Func<TResult> workFunction, Action<TResult> completedAction,
                bool runCompletedActionInUIThread = true)
        {
            var taskScheduler = runCompletedActionInUIThread
                    ? TaskScheduler.FromCurrentSynchronizationContext()
                    : TaskScheduler.Current;

            var task = Task.Run(workFunction);
            task.ContinueWith(unusedTask => completedAction(task.Result), taskScheduler);
            return task;
        }

        /// <summary>
        /// The Run
        /// </summary>
        /// <typeparam name="TWorkResult"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="workFunction">The workFunction<see cref="Func{TWorkResult}"/></param>
        /// <param name="completedAction">The completedAction<see cref="Func{TWorkResult, TResult}"/></param>
        /// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
        /// <returns>The <see cref="Task{TResult}"/></returns>
        public static Task<TResult> RunAsync<TWorkResult, TResult>(this Func<TWorkResult> workFunction,
                Func<TWorkResult, TResult> completedAction,
                bool runCompletedActionInUIThread = true)
        {
            var taskScheduler = runCompletedActionInUIThread
                    ? TaskScheduler.FromCurrentSynchronizationContext()
                    : TaskScheduler.Current;

            return Task.Run(workFunction).ContinueWith(workTask => completedAction(workTask.Result), taskScheduler);
        }

        /// <summary>
        /// The Run
        /// </summary>
        /// <param name="workTask">The workTask<see cref="Task"/></param>
        /// <param name="completedAction">The completedAction<see cref="Action"/></param>
        /// <param name="runCompletedActionInUIThread">The runCompletedActionInUIThread<see cref="bool"/></param>
        /// <returns>The <see cref="Task"/></returns>
        public static Task RunAsync(this Task workTask, Action completedAction,
                bool runCompletedActionInUIThread = true)
        {
            var taskScheduler = runCompletedActionInUIThread
                    ? TaskScheduler.FromCurrentSynchronizationContext()
                    : TaskScheduler.Current;
            if (workTask.Status == TaskStatus.Created)
                workTask.Start();

            return workTask.ContinueWith(unusedTask => completedAction(), taskScheduler);
        }

        #endregion
    }
}

代码来自我的一个开源项目wif ,里边有大量的扩展。

楚人Leo | 园豆:803 (小虾三级) | 2021-07-02 10:14

谢谢了

支持(0) 反对(0) 灬丶 | 园豆:9 (初学一级) | 2021-07-02 10:14
_mainViewModel.BusyContent = "体积计算中...";
_mainViewModel.IsIndeterminate = true;
_mainViewModel.IsBusy = true;
TaskExtensions.RunAsync(() =>
{
  //TODO 耗时操作,如体积计算
}, () => 
{ 
    _mainViewModel.IsBusy = false; 
});

调用方式

支持(0) 反对(0) 楚人Leo | 园豆:803 (小虾三级) | 2021-07-02 10:22

@楚人Leo: 好的我,我试下

支持(0) 反对(0) 灬丶 | 园豆:9 (初学一级) | 2021-07-02 10:23

@楚人Leo: 耗时的操作不应该
放在ContinueWith里面吗?

支持(0) 反对(0) 灬丶 | 园豆:9 (初学一级) | 2021-07-02 10:28

@灬丶:

Task.Run(workAction).ContinueWith(unusedTask => completedAction(), taskScheduler);

Task.Run和ContinueWith默认都是从线程池取一个线程执行操作,只是这里ContinueWith是通过taskScheduler切换到UI线程,所以ContinueWith实际上已经是UI线程了。

TaskScheduler.FromCurrentSynchronizationContext()

通过这行代码拿到UI线程同步上下文。

支持(0) 反对(0) 楚人Leo | 园豆:803 (小虾三级) | 2021-07-02 10:47

@楚人Leo: 嗯嗯,谢了

支持(0) 反对(0) 灬丶 | 园豆:9 (初学一级) | 2021-07-02 10:48
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册