在表单加载时启动后台线程

Start background thread on form load

需要向您寻求帮助,因为我现在为此苦苦挣扎了太久。 浏览了很多教程,但最终……一无所获。

所以,我有一个带有 GetServicesToList() 的 ServiceProcess class。此方法使用服务列表填充服务对象。

我现在正在做的是,我在应用程序 运行 时读取一个文件(包含服务)的缓存,并将数据显示在 datagridView 中。按下表单按钮时也会调用 GetServicesToList()。

由于服务器可用性问题,此任务最多需要 10 分钟。

在 BackgroundWorker class 的帮助下,我想要实现的是在 运行 时间启动此方法,每次完成后一遍又一遍地执行此操作以更新我的DataGridView 以及更新缓存(outputFile)。 所有这一切都没有用户被这个过程打断。

我已经在 BackgroundWord_DoWork() 中尝试调用此方法,但由于我的 ServiceProcess Class 使用 ServiceBase (class ServicesProcess : ServiceBase) 我无法声明此方法针对 BackgroundWorker.

希望我已经用足够的细节表达了自己的想法,这样你们就可以了解我正在努力实现的目标。有什么不明白的可以追问。

有人可以帮我解决这个问题吗?

public class ServicesProcess : ServiceBase, IEquatable<ServiceBase>
{
    private static string _machine = Services.GetServiceConfig();//ConfigurationManager.AppSettings.Get("machineName");
    private static List<Service> _servicesList;
    private static ServiceController[] _services;
    private List<ServiceController> _holder;
    private List<string> _configList;
    private static ObjectToSerialize _objectToSerialize;

    public List<Service> GetServicesToList()
    {
        //_services = ServiceController.GetServices(_machine);
        var result = MemoryCache.Default.Get(Name) as List<Service>;
        if (result != null)
            return result;

        try
        {

            _configList = new List<string>(Services.GetAllServicesConfig());
            _holder = new List<ServiceController>();
            foreach (string t in _configList)
            {
                _services = ServiceController.GetServices(t);
                _holder.AddRange(_services);
            }
        }
        catch (InvalidOperationException e)
        {

        }
        const string sPattern = "CSP";
        int i = 0;

        var cspServices = _holder.Where(x => x.DisplayName.Trim().StartsWith(sPattern)).ToList();

        _servicesList = new List<Service>();

        for (i = 0; i < cspServices.Count; i++)
        {
            Service obj = new Service
            {
                ServiceName = cspServices.ElementAt(i).DisplayName,
                ServiceVersion =
                    GetFileVersion(
                        GetFilePath(cspServices.ElementAt(i).ServiceName, cspServices.ElementAt(i).MachineName),
                        @"\" + cspServices.ElementAt(i).MachineName + "\"),
                ServiceStatus = cspServices.ElementAt(i).Status.ToString()
            };

            _servicesList.Add(obj);

        }

        _objectToSerialize = new ObjectToSerialize { Services = _servicesList };

        Serializer serializer = new Serializer();


        serializer.SerializeObject("outputFile.txt", _objectToSerialize);

        MemoryCache.Default.Set(Name, _servicesList, DateTimeOffset.Now.Add(new TimeSpan(0, 0, 30, 0)));

        return _servicesList;
    }

这是获取所有服务的方法。现在在设计class中,我想使用这个方法,因为线程或任务或后台工作所以这个方法将作为后台进程执行。不知道该怎么做...

并帮助您可视化应用程序本身...

我不完全确定你的目标,但是如果 GetServicesToList() 应该是 运行 在后台线程中,你不能只实现 async / await?

public async Task<List<Service>> GetServicesToList()
{
    return await Task.Run(() => {
        // all your old code
    });
}

当你调用它时

var serviceList = await GetServicesToList();

我假设你正在做某种数据绑定,所以当 serviceList 被水合时,只需将它传递给视图。


这是一个独立的概念。

using System;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            SimulateTenButtonClicks();
            Console.ReadKey();
        }

        private static async void SimulateTenButtonClicks()
        {
            var foo = new Foo();
            for (var i = 0; i < 10; i++)
            {
                var result = foo.DoStuff(i);
                Console.WriteLine(await result);
            }
        }

        public class Foo
        {
            public async Task<string> DoStuff(int i)
            {
                await Task.Delay(500); // simulate load
                return await Task.Run(() =>
                {
                    return String.Format("I have been hit {0} times", i);
                });
            }
        }
    }
}