【问题标题】:Close WPF application until the function completed关闭 WPF 应用程序,直到功能完成
【发布时间】:2018-11-15 20:05:36
【问题描述】:

我是C#的新手,我主要用VB开发.net应用程序。

我开发了 .net WPF 应用程序来连接微软认知服务来获取图像描述并保存到 sql server。

因为我会将它作为计划任务运行,因此我希望它在完成该过程后自动关闭。

应用程序可以正常工作以获取图像描述和更新表。

但如果我添加关闭应用程序功能,它将立即关闭而不启动进程。

我可以知道应用程序如何在关闭应用程序之前等待进程完成吗?

提前致谢。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.IO;
using Microsoft.ProjectOxford.Vision;
using Microsoft.ProjectOxford.Vision.Contract;

using System.Diagnostics;


namespace TagPhotoScheduler
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Boolean Finished = false;

        public MainWindow()
        {
            InitializeComponent();
            ReadFile();    
            CloseApp();
        }

        public void CloseApp()
        {
            //close application after run
            if (Finished == true)
            {                
                Application.Current.Shutdown();
                //this.Close();
            }
        }

        public void ReadFile()
        {
            DataClassesTagPhotoDataContext dc = new DataClassesTagPhotoDataContext();

            var query = from qPhoto in dc.db_PhotoLibrary_Photos
                        where qPhoto.ML_Processed == false
                        select qPhoto;

            foreach (var q in query)
            {    
                string pFileName = string.Empty;
                string photoURL = string.Empty;

                pFileName = q.PhotoID + "." + q.FileType;

                _status.Text += pFileName + " | ";

                photoURL = "https://example.com/storage/";

                if (q.ProjectID == null || q.ProjectID == 0)
                {
                    GetTag(q.PhotoID, photoURL + pFileName);

                    _status.Text += photoURL + pFileName + " \n";
                }
                else //had projectid
                {                        
                    photoURL +=  q.ProjectID + "/";

                    if (q.AlbumID == null || q.AlbumID == 0)
                    {
                        //photoURL += "/" + q.AlbumID + "/";
                        GetTag(q.PhotoID, photoURL + pFileName);
                        _status.Text += photoURL + pFileName + " \n";

                    }
                    else //albumid
                    {
                        photoURL +=  q.AlbumID + "/";
                        GetTag(q.PhotoID, photoURL + pFileName);
                        _status.Text += photoURL + pFileName + " \n";
                    }                            
                }    
            }
            //Finished = true;
            _status.Text += "\n\nFinished";
        }    

        public async void GetTag(int PhotoID, string URL)
        {
            VisionServiceClient VisionServiceClient = new VisionServiceClient("xxxxxxxxxxxxxxxxxxxx", "https://eastasia.api.cognitive.microsoft.com/vision/v1.0");

            DataClassesTagPhotoDataContext dc = new DataClassesTagPhotoDataContext();

            try
            {

                AnalysisResult analysisResult = await VisionServiceClient.DescribeAsync(URL, 3);

                if (analysisResult.Description != null)
                {    
                    foreach (var tag in analysisResult.Description.Tags)
                    {
                        tags += tag + ", ";

                        string QueryAnalysis = string.Empty;

                        db_PhotoLibrary_Photo_Tag newQ = new db_PhotoLibrary_Photo_Tag();
                        newQ.TagOn = DateTime.Now;
                        newQ.TagBy = 0;
                        newQ.PhotoID = PhotoID;
                        newQ.ML_Tag = true;
                        newQ.TagType = 0;
                        newQ.TagName = tag;
                        dc.db_PhotoLibrary_Photo_Tags.InsertOnSubmit(newQ);
                        dc.SubmitChanges();    

                        db_PhotoLibrary_Photo result = (from p in dc.db_PhotoLibrary_Photos
                                                        where p.PhotoID == PhotoID
                                                        select p).SingleOrDefault();    
                        result.ML_Processed = true;    
                        dc.SubmitChanges();    
                    }    
                    _status.Text = tags;
                }
            }
            catch { }    
        }    
    }    
}

最后,我将其更改为控制台应用程序,它可以完成我的工作。

【问题讨论】:

  • 看来您正在以一种即发即弃的方式使用async void GetTag,这看起来像是这里的核心问题。您可能应该将其设为async Task,然后在退出应用程序之前跟踪所有待处理的任务以完成。滥用 async void 是一个常见的陷阱,在 SO 上已广泛介绍。
  • ReadFileGetTag 需要为 async Task。然后将ReadFileCloseApp 从构造函数中取出。然后您的MainWindow 可以将初始化任务公开为seen here。该任务将代表文件访问,并将在您的组合根中等待,对于 WPF,它通常是 App.xaml.cs。最后,当初始化任务完成后,应用就可以退出了。
  • 另一个考虑因素是为什么你在 WPF 看起来并不需要 UI 时使用它。使用控制台应用程序,您没有任何异步构造函数的复杂性,并且可以轻松地 await ReadFile 然后退出。
  • 感谢 JSteward。我将其更改为控制台应用程序,它可以完成这项工作。

标签: c# wpf async-await


【解决方案1】:

您可以用任务包装 ReadFile 函数并使用延续:

        public MainWindow()
        {
            InitializeComponent();
            Task.Run(ReadFile).ContinueWith(CloseApp);    

        }

您确定这需要是 WPF 应用程序吗?控制台无法完成这项工作?

【讨论】:

  • 谢谢。我将其更改为控制台应用程序,它可以完成这项工作。
猜你喜欢
  • 2012-07-11
  • 1970-01-01
  • 2013-06-13
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 1970-01-01
  • 2019-10-04
  • 1970-01-01
相关资源
最近更新 更多