Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 显示';加载…';异步初始化模型时视图中的屏幕_C#_Wpf_Xaml - Fatal编程技术网

C# 显示';加载…';异步初始化模型时视图中的屏幕

C# 显示';加载…';异步初始化模型时视图中的屏幕,c#,wpf,xaml,C#,Wpf,Xaml,我有一个视图模型 protected override void Initialize() { this.InnerViewModel.LoadInformation(); this.IsInformationLoaded = true; } 但是,this.InnerViewModel.LoadInformation()是非常CPU和IO密集型的操作。可能需要几秒钟才能完成 该模型的视图绑定到IsInformation Loaded,以显示“Loading…”屏幕 您可以想

我有一个视图模型

protected override void Initialize()
{
    this.InnerViewModel.LoadInformation();

    this.IsInformationLoaded = true;
}
但是,
this.InnerViewModel.LoadInformation()是非常CPU和IO密集型的操作。可能需要几秒钟才能完成

该模型的视图绑定到
IsInformation Loaded
,以显示“Loading…”屏幕

您可以想象,我当前的实现没有显示“加载…”屏幕,而是在操作完成之前冻结UI

如何更改
Initialize
方法,使
LoadInformation
异步?请记住,
InnerViewModel
也是视图绑定的

编辑:

以下作品

protected override async void Initialize()
{
    await Task.Run(() =>
    {
        this.InnerViewModel.LoadInformation();
    });

    this.IsInformationLoaded = true;
}

// In InnerViewModel
public override void LoadInformation()
{
    Thread.Sleep(3000);

    Application.Current.Dispatcher.Invoke(() =>
    {
        this.SomethingObservable.Clear();
        this.SomethingObservable.Add(...something ...);
    });
}
但是,如果可能的话,我真的想去掉
Application.Current.Dispatcher
。或者以某种方式将其移动到
Initialize()
中。我不想让
InnerModel
知道它是如何执行的

此外,如果InnerViewModel的LoadInformation不知道它正在异步执行和/或不对其进行任何特殊处理,则最好是这样。可能吗

在.NET Framework 4.5+中,可以通过调用方法从后台线程访问数据绑定集合,例如:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new WindowViewModel();
    }
}

public class WindowViewModel
{
    private readonly object _lock = new object();

    public ObservableCollection<string> Items { get; } = new ObservableCollection<string>();

    public WindowViewModel()
    {
        BindingOperations.EnableCollectionSynchronization(Items, _lock);
        Task.Run(() =>
        {
            for (int i = 0; i < 100; ++i)
            {
                Items.Add(i.ToString());
                Thread.Sleep(2000);
            }
        });
    }
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
DataContext=新的WindowViewModel();
}
}
公共类WindowViewModel
{
私有只读对象_lock=新对象();
公共ObservableCollection项{get;}=new ObservableCollection();
公共WindowViewModel()
{
BindingOperations.EnableCollectionSynchronization(项,_锁);
Task.Run(()=>
{
对于(int i=0;i<100;++i)
{
Items.Add(i.ToString());
《睡眠》(2000年);
}
});
}
}


另一个选项是使用dispatcher将访问数据绑定集合的操作封送回UI线程:

Task.Run(() =>
            {
                for (int i = 0; i< 100; ++i)
                {
                    Application.Current.Dispatcher.Invoke(new Action(() => Items.Add(i.ToString())));
                    Thread.Sleep(2000);
                }
            });
Task.Run(()=>
{
对于(int i=0;i<100;++i)
{
Application.Current.Dispatcher.Invoke(新操作(()=>Items.Add(i.ToString()));
《睡眠》(2000年);
}
});

这种方法使方法意识到它确实是在后台线程上执行的。

如果在方法中设置
IsInformationLoaded=false
,然后
Task.Run(This.InnerViewModel.LoadInformation)。ContinueWith(()=>{This.IsInformationLoaded=true;})会发生什么情况?如果您将加载的布尔值设置为Task.Run之后的下一行,它将在任务准备就绪之前执行该行。如果这不是问题所在,您是否可以澄清您所说的“
Task.Run()
和类似方法[未成功]”的意思。我已通过question@cubrr编辑了您新发现的线程问题,您需要查看。这可能会起作用,但
InnerViewModel
会知道它是以异步方式执行的,如果可以的话,我很想避免这种情况……但是,
BindingOperations.EnableCollectionsSynchronization
如果在
任务中执行的方法中执行,则无法工作。在启动后台线程之前,在UI线程上调用它,如我的示例所示。不管怎样,要么是这个,要么是使用调度程序。
Task.Run(() =>
            {
                for (int i = 0; i< 100; ++i)
                {
                    Application.Current.Dispatcher.Invoke(new Action(() => Items.Add(i.ToString())));
                    Thread.Sleep(2000);
                }
            });