Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.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# 与ReactiveUI 6的线程关联_C#_Wpf_Reactive Programming_Reactiveui - Fatal编程技术网

C# 与ReactiveUI 6的线程关联

C# 与ReactiveUI 6的线程关联,c#,wpf,reactive-programming,reactiveui,C#,Wpf,Reactive Programming,Reactiveui,场景(WPF桌面应用程序.NET 4.6): 我有一个显示一些“任务”的列表框。 目标是启动一个异步进程,该进程将遍历所有任务,执行其中的每一个任务 这是一个长时间运行的过程,因此期望的行为是禁用大多数命令而不锁定UI,以便用户仍然可以取消它。 它应该标记每个任务(备用、运行、完成),以便可以动态更新UI,向最终用户提供反馈(使用基于“状态”枚举的样式) 问题 执行命令(ExecuteTasks)时,我会收到以下消息: 此类型的CollectionView不支持从不同于Dispatcher线程的

场景(WPF桌面应用程序.NET 4.6):

我有一个显示一些“任务”的列表框。 目标是启动一个异步进程,该进程将遍历所有任务,执行其中的每一个任务

这是一个长时间运行的过程,因此期望的行为是禁用大多数命令而不锁定UI,以便用户仍然可以取消它。 它应该标记每个任务(备用、运行、完成),以便可以动态更新UI,向最终用户提供反馈(使用基于“状态”枚举的样式)

问题

执行命令(
ExecuteTasks
)时,我会收到以下消息:

此类型的CollectionView不支持从不同于Dispatcher线程的线程更改其SourceCollection

我的问题是:如何使用ReactiveUI解决这个问题?我相信答案就在调度程序的某个地方,但到目前为止我还没有弄清楚

下面是代码的样子:

public ReactiveCommand<object> AddTask { get; }
public ReactiveCommand<object> ExecuteTasks { get; }
public IPlugin SelectedTask
{
    get { return selectedTask; }
    set { this.RaiseAndSetIfChanged(ref selectedTask, value); }
}
public ReactiveList<IPlugin> Tasks
{
    get { return tasks; }
}
public ReactiveList<PluginFactoryGroup> TaskFactories
{
    get
    {
        return taskFactories;
    }
}

public AppViewModel(IExecutionContext context, IEnumerable<PluginFactoryGroup> taskFactories)
{

    this.context = context;

    // initialize lists
    tasks = new ReactiveList<IPlugin>() { ChangeTrackingEnabled = true };
    this.taskFactories = new ReactiveList<PluginFactoryGroup>(taskFactories);

    // create observables to determine whether or not commands can be executed
    var canEdit = /*...*/
    var canExecute = /*...*/

    // initialize commands
    AddTask = ReactiveCommand.Create(canEdit);
    AddTask.Subscribe(_ => {
        if (SelectedFactory != null)
        {
            var t = SelectedFactory.Create(this.context);
            Tasks.Add(t);
            SelectedTask = t;
        }
    });

    ExecuteTasks = ReactiveCommand.CreateAsyncTask(canExecute, _ =>
    {
        return Task.Run(() =>
        {
            object result = null;
            foreach (var item in Tasks)
            {
                item.Clear();
                item.Validate();
            }

            if (Tasks.Any(e => e.Status == TaskStatus.Error))
            {
                Tasks.Reset();
                return result;
            }

            foreach (var item in Tasks)
            {
                item.Status = XrmTools.Plugins.TaskStatus.Running;
                item.Execute();
                item.Status = XrmTools.Plugins.TaskStatus.Completed;
            }
            return result;
        });
    });

}
public ReactiveCommand AddTask{get;}
public ReactiveCommand ExecuteTasks{get;}
公共IPlugin SelectedTask
{
获取{return selectedTask;}
设置{this.RaiseAndSetIfChanged(ref selectedTask,value);}
}
公共反应列表任务
{
获取{返回任务;}
}
公共反应列表任务工厂
{
得到
{
返回工厂;
}
}
公共AppViewModel(IExecutionContext上下文,IEnumerable TaskFactorys)
{
this.context=上下文;
//初始化列表
tasks=new ReactiveList(){changetrackingabled=true};
this.taskFactorys=新的反应列表(taskFactorys);
//创建可观察对象以确定是否可以执行命令
var canEdit=/**/
变量canExecute=/**/
//初始化命令
AddTask=ReactiveCommand.Create(canEdit);
AddTask.Subscribe(=>{
如果(SelectedFactory!=null)
{
var t=SelectedFactory.Create(this.context);
任务。添加(t);
选择任务=t;
}
});
ExecuteTasks=ReactiveCommand.CreateAsyncTask(canExecute,=>
{
返回任务。运行(()=>
{
对象结果=空;
foreach(任务中的变量项)
{
item.Clear();
item.Validate();
}
if(Tasks.Any(e=>e.Status==TaskStatus.Error))
{
Tasks.Reset();
返回结果;
}
foreach(任务中的变量项)
{
item.Status=XrmTools.Plugins.TaskStatus.Running;
item.Execute();
item.Status=XrmTools.Plugins.TaskStatus.Completed;
}
返回结果;
});
});
}
所有UI更新(ReactiveList添加/删除或IPlugin属性更改)都需要在UI线程中进行。在您的情况下,假设
item.Execute()
是您希望在后台执行的冗长操作,您应该使用async/await而不是Task.Run,例如:您的代码应该如下所示:

ExecuteTasks = ReactiveCommand.CreateAsyncTask(canExecute, async _ =>
{
    object result = null;
    foreach (var item in Tasks)
    {
        item.Clear();
        item.Validate();
    }

    if (Tasks.Any(e => e.Status == TaskStatus.Error))
    {
        Tasks.Reset();
        return result;
    }

    foreach (var item in Tasks)
    {
        item.Status = XrmTools.Plugins.TaskStatus.Running;
        await ExecuteAsync(item);
        item.Status = XrmTools.Plugins.TaskStatus.Completed;
    }
    return result;
});

Task ExecuteAsync(IPlugin item)
{
    return Task.Run(() => item.Execute());
}

如果你需要更多灵感,不妨看看这个。

太棒了。错误消失了,它不会像预期的那样阻塞UI,非常感谢。但是有一件事,状态的改变-
item.status=/*new\u status*/
并没有向用户界面发出信号。集合正在更改,但用户界面未更改。我让它工作的方法是在每次更改(两次)后添加
Tasks.Reset()
,这似乎不正确。