Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.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# WPF从异步任务更新ObservableList引发XamlParseException_C#_Wpf_Caliburn.micro_Taskfactory - Fatal编程技术网

C# WPF从异步任务更新ObservableList引发XamlParseException

C# WPF从异步任务更新ObservableList引发XamlParseException,c#,wpf,caliburn.micro,taskfactory,C#,Wpf,Caliburn.micro,Taskfactory,当我尝试从一个单独的线程(然后是ui线程)更新我在XAML中使用的ObservableCollection时,我得到一个XamlParseException,它表示DependencySource必须在DependencyObject所在的同一线程上创建。我正在使用Caliurn Micro将ViewModel绑定到视图 我尝试了几种方法来达到我的目标,下面的方法似乎是我最合理的方法。我正在将SyncronizationContext从UI传递到任务,这样它就可以在完成繁重的工作负载后更新UI

当我尝试从一个单独的线程(然后是ui线程)更新我在XAML中使用的ObservableCollection时,我得到一个XamlParseException,它表示DependencySource必须在DependencyObject所在的同一线程上创建。我正在使用Caliurn Micro将ViewModel绑定到视图

我尝试了几种方法来达到我的目标,下面的方法似乎是我最合理的方法。我正在将SyncronizationContext从UI传递到任务,这样它就可以在完成繁重的工作负载后更新UI

我做错了什么

查看

<Window x:Class="QuickScope.Views.NavigatorView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:QuickScope.Views"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:quickScope="clr-namespace:QuickScope"
    mc:Ignorable="d">
<Grid>
    <TextBox Grid.Row="0" 
             Name="TextBox"
             HorizontalContentAlignment="Stretch"
             VerticalContentAlignment="Center"
             Margin="5,0,5,5"
             Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    </TextBox>
    <Popup PlacementTarget="{Binding ElementName=TextBox}">
        <ListView x:Name="ItemList" ItemsSource="{Binding Items}" SelectedItem ="{Binding SelectedItem}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <WrapPanel>
                        <Image Source="{Binding IconSource}" Width="20" Height="20"></Image>
                        <Label Content="{Binding SearchName}"></Label>
                    </WrapPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Popup>
</Grid>

视图模型

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Threading;
using Caliburn.Micro;
using QuickScope.Views;

namespace QuickScope.ViewModels
{
public class NavigatorViewModel : Screen
{
    private readonly ItemService _itemService;

    public NavigatorViewModel()
    {
        _itemService = new ItemService();
        Items = new ObservableCollection<ItemViewModel>();

    }

    public ObservableCollection<ItemViewModel> Items { get; }

    public ItemViewModel SelectedItem { get; set; }

    private string _searchText;

    public string SearchText
    {
        get => _searchText;
        set
        {
            _searchText = value;
            NotifyOfPropertyChange(() => SearchText);
            UpdateItemList(_searchText);
        }
    }

    private void UpdateItemList(string searchText)
    {
        Items.Clear();

        var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

        Task.Factory.StartNew(() =>
        {
            //the long running workload
            var items = _itemService.GetByFilter(searchText);

            //update the ui
            Task.Factory.StartNew(() =>
            {
                foreach (var item in items)
                    Items.Add(item);

                if (items.Any())
                {
                    SelectedItem = items.First();
                    NotifyOfPropertyChange(() => SelectedItem);
                }
            }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
        });
    }
}
}
使用系统;
使用System.Collections.ObjectModel;
使用System.Linq;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows;
使用System.Windows.Input;
使用System.Windows.Interop;
使用System.Windows.Threading;
使用Caliburn.Micro;
使用QuickScope.Views;
命名空间QuickScope.ViewModels
{
公共类NavigatorViewModel:屏幕
{
私有只读项服务_ItemService;
公共导航器视图模型()
{
_itemService=新的itemService();
Items=新的ObservableCollection();
}
公共可观察集合项{get;}
公共项目视图模型SelectedItem{get;set;}
私有字符串_searchText;
公共字符串搜索文本
{
获取=>\u搜索文本;
设置
{
_搜索文本=值;
NotifyOfPropertyChange(()=>SearchText);
UpdateItemList(_searchText);
}
}
私有void UpdateItemList(字符串搜索文本)
{
Items.Clear();
var uiScheduler=TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(()=>
{
//长期运行的工作负载
var items=\u itemService.GetByFilter(searchText);
//更新用户界面
Task.Factory.StartNew(()=>
{
foreach(项目中的var项目)
项目。添加(项目);
if(items.Any())
{
SelectedItem=items.First();
NotifyOfPropertyChange(()=>SelectedItem);
}
},CancellationToken.None,TaskCreationOptions.None,uiScheduler);
});
}
}
}
编辑

我尝试了Shadrix的方法,但不幸的是,它也不起作用。我还尝试了Peter Dunihos的答案,但也没有成功(我得到了与上面描述的相同的XamlParseException)

我最后尝试的是CM的内置方法,它基本上包装了Dispatcher.CurrentDispatcher。显然(考虑到我最近两次失败的尝试),它也失败了。当前实现类似于以下内容(我删除了其他不相关的属性和方法):

公共类导航器视图模型:屏幕
{
公共导航器视图模型()
{
Items=新的ObservableCollection();
}
公共ObservableCollection项{get;set;}
公共项目视图模型SelectedItem{get;set;}
私有字符串_searchText;
公共字符串搜索文本
{
获取=>\u搜索文本;
设置
{
_搜索文本=值;
NotifyOfPropertyChange(()=>SearchText);
UpdateItemList(_searchText);
}
}
私有void UpdateItemList(字符串搜索文本)
{
Items.Clear();
var updater=new ItemUpdater();
updater.ItemsUpdated+=(s,e)=>{
OnUIThread(()=>
{
var items=((ItemsUpdatedEventArgs)e);
foreach(项目中的var项目)
{
项目。添加(项目);
}
财产变更通知(()=>项);
});
};
var updateThread=新线程(updater.GetItems);
updateThread.Start(搜索文本);
}
}
公共类项目更新程序
{
公共事件事件处理程序项支持;
私有只读项服务_ItemService;
公共项目更新程序()
{
_itemService=新的itemService();
}
public void GetItems(对象搜索文本)
{
var items=\u itemService.GetByFilter((字符串)searchText);
ItemsUpdated?调用(这个,新的ItemsUpdatedEventArgs(items));
}
}
公共类ItemsUpdatedEventArgs:EventArgs
{
公共项目supdatedeventargs(IList项目)
{
项目=项目;
}
公共IList项{get;}
}
我无法解决这个问题,这让我发疯,因此,如果有人愿意帮助一名年轻的少年,我将高度赞赏。:)

您可以找到完整的源代码


谢谢大家!

使用当前UI线程的
调度程序

//update the ui
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
    foreach (var item in items)
    {
        Items.Add(item);
    }

    if (items.Any())
    {
        SelectedItem = items.First();
        NotifyOfPropertyChange(() => SelectedItem);
    }
}));

谢谢你的回答,不幸的是它没有解决我的问题。我仍然得到所描述的异常(有关更多信息,请参见编辑的问题)
//update the ui
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
    foreach (var item in items)
    {
        Items.Add(item);
    }

    if (items.Any())
    {
        SelectedItem = items.First();
        NotifyOfPropertyChange(() => SelectedItem);
    }
}));