C# 调度程序WPF异步

C# 调度程序WPF异步,c#,wpf,asynchronous,.net-3.5,C#,Wpf,Asynchronous,.net 3.5,每次计时器调用时,UpdateDocumentsListFromServerUI冻结3秒。如何在.NET3.5下以异步方式更新列表 视图模型: public class ShippingDocumentsRegisterViewModel : ViewModelBase { ShippingDocumentsModel model = new ShippingDocumentsModel(); DispatcherTimer timer = new Di

每次计时器调用时,
UpdateDocumentsListFromServer
UI冻结3秒。如何在.NET3.5下以异步方式更新列表

视图模型:

public class ShippingDocumentsRegisterViewModel : ViewModelBase
    {
        ShippingDocumentsModel model = new ShippingDocumentsModel();

        DispatcherTimer timer = new DispatcherTimer();

        BackgroundWorker BW = new BackgroundWorker();

        public ShippingDocumentsRegisterViewModel()
        {
            timer = new DispatcherTimer();
            timer.Tick += new EventHandler(UpdateDocumentsListFromServer);
            timer.Interval = new TimeSpan(0, 0, 10);
            timer.Start();

            this.Columns = model.InitializeColumns();
            BW.DoWork += UpdateDocumentsList;
            BW.RunWorkerAsync();
        }

        public void UpdateDocumentsList(object o, EventArgs args)
        {
            this.ShippingDocuments = model.GetDocuments();
        }

        public void UpdateDocumentsListFromServer(object o, EventArgs args)
        {
            // Taking a lot of time. How to do it async?
            var tempDocuments = model.GetDocumentsFromServer();
            foreach (var item in tempDocuments)
            {
                this.shippingDocuments.Add(item);
            }
            //
        }

        private ObservableCollection<ShippingDocument> shippingDocuments;

        public ObservableCollection<ShippingDocument> ShippingDocuments
        {
            get
            {
                return shippingDocuments;
            }

            private set
            {
                shippingDocuments = value;
                RaisePropertyChanged("ShippingDocuments");
            }
        }

        public ObservableCollection<ShippingDocumentColumDescriptor> Columns { get; private set; }

    }
公共类发货文档注册视图模型:ViewModelBase
{
ShippingDocumentsModel模型=新的ShippingDocumentsModel();
调度程序计时器=新调度程序();
BackgroundWorker BW=新的BackgroundWorker();
公共ShippingDocumentsRegisterViewModel()
{
计时器=新调度程序();
timer.Tick+=新事件处理程序(UpdateDocumentsListFromServer);
timer.Interval=新的时间跨度(0,0,10);
timer.Start();
this.Columns=model.InitializeColumns();
BW.DoWork+=更新的文档列表;
RunWorkerAsync();
}
public void UpdateDocumentsList(对象o、事件args args)
{
this.ShippingDocuments=model.GetDocuments();
}
public void UpdateDocumentsListFromServer(对象o、事件args args)
{
//要花很多时间。如何异步进行?
var tempDocuments=model.GetDocumentsFromServer();
foreach(tempDocuments中的var项)
{
本.发货单据.新增(项);
}
//
}
私人可观测收集运输文件;
公共可观测收集装运文件
{
收到
{
返回装运文件;
}
专用设备
{
装运单据=价值;
RaiseProperty变更(“装运文件”);
}
}
公共ObservableCollection列{get;private set;}
}
GetDocumentsFromServer看起来像

    public ObservableCollection<ShippingDocument> GetDocumentsFromServer()
    {
        System.Threading.Thread.Sleep(3000);
        return new ObservableCollection<ShippingDocument> { new ShippingDocument { Name = "Test" } };
    }
public observeCollection GetDocumentsFromServer()
{
系统线程线程睡眠(3000);
返回新的ObservableCollection{new ShippingDocument{Name=“Test”};
}

使用常规的
计时器
,仅发送对
发货文档的访问权

如评论中所述,您可以使用而不是
发货人
DispactherTimer
将访问UIThread,其中作为计时器使用不同于threadpool的线程

此外,还可以从不同的线程向UIThread分派操作

Application.Current.Dispatcher.BeginInvoke(new Action(() =>
           {
               //Do some UI stuffs                   
           }));

希望有帮助

您还可以使用后台工作程序向UI报告进度

public ShippingDocumentsRegisterViewModel()
{

    BW.DoWork += UpdateDocumentsListFromServer;
    BW.RunWorkerCompleted += BW_RunWorkerCompleted;

    BW.WorkerReportsProgress = true;
    BW.ProgressChanged += UpdateGui;
    BW.RunWorkerAsync();
}
public void UpdateGui(object o, EventArgs args)
{
    foreach (var item in tempDocuments)
    {
        this.shippingDocuments.Add(item);
    }
}
public void UpdateDocumentsListFromServer(object o, EventArgs args)
{

    while (true) {
        System.Threading.Thread.Sleep(3000);

        tempDocuments = GetDocumentsFromServer();
        BW.ReportProgress(0);

    }
}

int num = 0;
public ShippingDocument[] GetDocumentsFromServer()
    {
        System.Threading.Thread.Sleep(3000);
        return new ShippingDocument[1] { new ShippingDocument { Name = "Test" + num++} };
    }

private ShippingDocument[] tempDocuments = new ShippingDocument[0];

只需使用Task和Async/Await将其卸载到新线程,如下所示:

public async void UpdateDocumentsListFromServer(object o, EventArgs args)
        {
            // This will execute async and return when complete
            await Task.Run(()=>{
              var tempDocuments = model.GetDocumentsFromServer();
              foreach (var item in tempDocuments)
              {
                  this.shippingDocuments.Add(item);
              }
            });
            //
        }
请记住,这将在不同的线程上更新,然后在UI上更新。因此,不允许触摸UI线程上的任何内容,否则会出现线程问题。因此,如果shippingDocuments是在UI线程上创建的,并且不是线程安全的,则可以返回一组项目,然后添加它们:

public async void UpdateDocumentsListFromServer(object o, EventArgs args)
        {
            // Execute on background thread and put results into items
            var items = await Task.Run(()=>{
              var tempDocuments = model.GetDocumentsFromServer();                  
              return tempDocuments;
            });
            //add occurs on UI thread.
            this.shippingDocuments.AddRange(tempDocuments);
        }

它会冻结,因为您有
睡眠(3000)
。也许您想设置绑定(为此,它必须是一个属性)?另一个选项是将
GetDocumentsFromServer
定义为
async
,并在内部使用异步方法(例如
wait Task.Delay()
甚至
wait Task.Run(()=>Thread.Sleep())
。@Sinatr,是的,我知道Sleep(3000)freez UI。它模拟长期运行的工作。在.NET3.5中没有任何异步的等待方法。我建议使用,而不是
DispactherTimer
DispactherTimer
将访问UIThread,其中as
Timer
使用threadpool中的线程。添加到@Gopichandar注释:从另一个线程修改
ObservableCollection
是,但您可以这样做
foreach
。在.net 3.5中已经有其他关于异步的帖子。。。因为我认为这可能是一个重复(同时考虑到OP没有对不同的答案给出任何具体的反馈:-))显然,只要没有触发,带有RunWorkerCompleted的行是不相关的……有几件事1)我假设你没有使用.Net 3.5和这个确切的代码,但是你忘了提到OP问题的这一部分:-)。。。2) 当然,ShippingDocuments是UI