ReactiveUI "Compelling Example" 使用 Caliburn.Micro.ReactiveUI 搜索

ReactiveUI "Compelling Example" search with Caliburn.Micro.ReactiveUI

我有一个使用 Caliburn.Micro 构建的现有 Wpf 应用程序,我想开始集成 ReactiveUI。首先,我从 Caliburn.Micro 切换到 Caliburn.Micro.ReactiveUI 库。

我有一个 ListBox,它使用 Caliburn Micro 的约定绑定到 BindableCollection。我使用 CM 来定位 MyViewModel 的视图,并且 BindableCollection 是从使用 EntityFramework.

执行的搜索中填充的

我正在尝试实现所示的异步 "compelling example",但每当执行搜索时 ReactiveUI.dll 都会抛出未处理的 InvalidCastException。我看不到任何细节,因为我没有 ReactiveUI.pdb 符号文件。我将我的 BindableCollection 属性 包装在一个 ObservableAsPropertyHelper 中,这样当用户执行搜索时,ReactiveUI 将更新 BindableCollection 以便 Caliburn.Micro 可以像往常一样做。

有谁知道什么会导致无效转换异常?我对 CM 有点经验,但对 Rx 和 RxUI 完全是个新手。所以,我可能完全以错误的方式解决这个问题。

相关代码如下:

public class MainViewModel: ReactiveScreen
{
        private ObservableAsPropertyHelper<BindableCollection<MyViewModel>> _myViewModels;
        public BindableCollection<MyViewModel> MyViewModels
        {
            get { return _myViewModels.Value; }
        }

        [ImportingConstructor]
        public MainViewModel(IEventAggregator eventAggregator)
        {

            _myEntities = new myEntities();
            var searchService = new SearchService(_myEntities);
            Items.CollectionChanged += delegate
            {
                NotifyOfPropertyChange(() => Status);
            };
            var searchTerms = this
                .ObservableForProperty(x => x.SearchTerm)
                .Value()
                .Throttle(TimeSpan.FromSeconds(.5));
            var searchResults = searchTerms.SelectMany(searchTerm => searchService.SearchAsync(searchTerm));
            var latestMatches = searchTerms
               .CombineLatest(searchResults,
                   (searchTerm, searchResult) =>
                       searchResult.SearchTerm != searchTerm
                           ? null
                           : searchResult.Matches)
               .Where(matches => matches != null);
            _myViewModels= latestMatches.ToProperty(this, x => x.MyViewModels);

        }
}

SearchService 如下所示:

public class SearchService
    {
        private MyEntities _myEntities;
        public SearchService(MyEntities myEntities)
        {
            _myEntities= myEntities;
        }
        public async Task<SearchResult> SearchAsync(string searchTerm)
        {
            var query = await (from m in _myEntities.Employees select m).ToListAsync();
            if (!String.IsNullOrEmpty(searchTerm))
            {
                searchTerm = searchTerm.Trim();
                query = (List<Employee>) query.Where(
                    x => x.LastName.Contains(searchTerm) || x.FirstName.Contains(searchTerm))
                    .Select(x => x);
            }
            return new SearchResult
            {
                SearchTerm = searchTerm,
                Matches = new BindableCollection<MyViewModel>(query.Select(x => new MyViewModel{ Employee = x }))
            };

        }
    }

搜索结果:

public class SearchResult
    {
        public string SearchTerm { get; set; }
        public BindableCollection<MyViewModel> Matches { get; set; }
    }

谢谢,

肖恩

编辑:

在不同位置设置断点后,我得到了异常的详细信息。

留言:

{"An OnError occurred on an object (usually ObservableAsPropertyHelper) that would break a binding or command. To prevent this, Subscribe to the ThrownExceptions property of your objects"}

内部异常:

{"Unable to cast object of type WhereSelectListIterator2[HR.DataContext.Models.Employee,HR.DataContext.Models.Employee]' to type System.Collections.Generic.List1[HR.DataContext.Models.Employee]'."}

堆栈跟踪:

at ReactiveUI.RxApp.<>c__DisplayClass5.<.cctor>b__2()
   at System.Reactive.Concurrency.Scheduler.Invoke(IScheduler scheduler, Action action)
   at System.Reactive.Concurrency.DispatcherScheduler.<>c__DisplayClass1`1.<Schedule>b__0()
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)

您的问题在线:

query = (List<Employee>)
    query
        .Where(x => x.LastName.Contains(searchTerm)
            || x.FirstName.Contains(searchTerm))
        .Select(x => x);

查询类型似乎是 List<Employee>,但 query.Where(...).Select(...) returns 的类型不是。

您需要在末尾添加一个.ToList()。它应该是这样的:

query = //(List<Employee>) no need to cast now
    query
        .Where(x => x.LastName.Contains(searchTerm)
            || x.FirstName.Contains(searchTerm))
        .ToList();

我删除了 .Select(x => x),因为它什么也没做。