繁体   English   中英

在MVVM中阻止了UI

[英]blocked UI in MVVM

我正在尝试按照MVVM策略构建应用程序。 不幸的是,我的原始示例(请参见下文)阻止了UI,尽管我特别呼吁调度员。 不知道为什么..有什么建议吗?

class ViewModel : INotifyPropertyChanged
{
    private readonly Dispatcher _dispatcher;

    private string _name;

    public ViewModel()
    {
        _dispatcher = Dispatcher.CurrentDispatcher;
    }

    public string Name
    {

        get { return _name; }
        set
        {
            _name = value;
            InvokePropertyChanged("Name");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void InvokePropertyChanged(string propertyName)
    {
        var e = new PropertyChangedEventArgs(propertyName);
        PropertyChangedEventHandler changed = PropertyChanged;
        if (changed != null)
            changed(this, e);
    }

    public void send()
    {
        Action dispAc = () => NameAsync();
        _dispatcher.BeginInvoke(dispAc);
    }

    private void NameAsync()
    {
        Name = "name1";
        Thread.Sleep(5000);
    }
}

PS。 第一个回复澄清了一个问题,谢谢。 对于那些不使用4.5的人,我使用

Task.Factory.StartNew(dispatchAction);

休息是一样的。

不要将Dispatcher.CurrentDispatcher用于此任务。 Dispatcher.CurrentDispatcher您带来当前正在执行的线程,可能是UI线程。 这意味着,在UI线程中调用NameAsync()函数,当然仍然阻止UI。 您可以使用Task.Run()异步执行您的方法以避免阻止UI:

Action dispAc = () => NameAsync();
Task.Run(dispAc);

您正在调度... UI线程的工作。 在不同的线程上完成工作,然后,当您完成后,将UI更新分发到UI线程。

除了你甚至不必。

只要您不在3.0的框架上,绑定就会自动将INPC PropertyChanged事件封送到UI线程上。 因此,当从工作线程触摸这些属性时,您可以省去任何调度。

用你的例子......

public void send()
{
    // We're on the UI thread here
    Task.Run(() => NameAsync());
}

private void NameAsync()
{
    // we're on some anonymous threadpool thread right now
    Name = "name1";
    // the event is fired on the threadpool, but bindings automatically marshall
    // UI update code onto the UI thread, so it returns directly before UI is 
    // changed
    Thread.Sleep(5000);
    // and now our threadpool thread is sleeping.  Good night, sweet prince.
}

改变这个,

public void send()
{
    Action dispAc = () => NameAsync();
    _dispatcher.BeginInvoke(dispAc);
}

对此

public void send()
{
 Action dispAc = () => NameAsync();
  _dispatcher.BeginInvoke(dispAc, DispatcherPriority.Background);
}

如果您不需要UI thread来执行需要Dispatcher的方法,那么只需使用TPL

默认情况下,如果您没有指定DispatcherPriority ,它将使用Normal因此它将使用当前线程可能占用UI Thread例如,当它尝试为其他控件执行一些Render

顺便说一句,如果您使用的是.NET 4.5可以考虑使用awaitasync关键字。 如果没有,那么像其他人建议只是产生一个不同的线程来更新UI SilverlightWinRT相比, WPFDispatcher足够智能,可以对主线程进行UI更新。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM