我是Rx.Net&的新手。 RxUI。在我学习这两个库的过程中,我尝试构建一个从网站中提取图像的演示应用程序。我使用WPF结合Rx.Net和RxUI来构建Views和ViewModels,并使用HtmlAgilityPack来处理html文档。我的代码如下所示
视图模型:
public class MainViewModel : ReactiveObject
{
public MainViewModel()
{
var canSearch =
this.WhenAnyValue(x => x.TargetUrl, targetWebSite => !string.IsNullOrEmpty(targetWebSite));
_searchCommand = ReactiveCommand.CreateFromTask(GetHtmlDocument, canSearch);
_imageSequence = _searchCommand
.SelectMany(ImageExtractService.ExtractAllImageAddress).Distinct().Publish().RefCount();
_imageSequence.Subscribe(
url => ImageList.Add(new ScrappedWebImageViewModel { ImageUrl = url }),
ex => this.Log().Error(ex)); //Causing problem, need better solution
}
private readonly IObservable<string> _imageSequence;
private IHtmlDownloadService _htmlDownloadService;
private IHtmlDownloadService HtmlDownloadService =>
_htmlDownloadService ?? (_htmlDownloadService = Locator.Current.GetService<IHtmlDownloadService>());
private IImageExtractService _imageExtractService;
private IImageExtractService ImageExtractService =>
_imageExtractService ?? (_imageExtractService = Locator.Current.GetService<IImageExtractService>());
public ReactiveList<ScrappedWebImageViewModel> ImageList =
new ReactiveList<ScrappedWebImageViewModel>();
private readonly ReactiveCommand<Unit, HtmlDocument> _searchCommand;
public ICommand SearchCommand => _searchCommand;
private async Task<HtmlDocument> GetHtmlDocument()
{
return await HtmlDownloadService.GetHtmlDocument(TargetUrl);
}
}
查看:
public partial class MainWindow : IViewFor<MainViewModel>
{
public MainWindow()
{
InitializeComponent();
ViewModel = new MainViewModel();
this.WhenActivated(d =>
{
d(this.Bind(ViewModel, x => x.Status, x => x.TblStatus.Text));
d(this.Bind(ViewModel, x => x.Progress, x => x.TblProgress.Text));
d(this.Bind(ViewModel, x => x.TargetUrl, x => x.TbxTargetWebSite.Text));
d(this.OneWayBind(ViewModel, x => x.ImageList, x => x.LbxImageList.ItemsSource));
d(this.BindCommand(ViewModel, x => x.SearchCommand, x => x.BtnBeginSearch));
});
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(MainViewModel), typeof(MainWindow));
public MainViewModel ViewModel
{
get => (MainViewModel) GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (MainViewModel)value;
}
}
HtmlDownloadService:
internal class HtmlDownloadService : IHtmlDownloadService
{
private readonly HtmlWeb _webClient = new HtmlWeb();
public async Task<HtmlDocument> GetHtmlDocument(string url)
{
return await Task.Run(() => _webClient.Load(url));
}
}
ImageExtractService:
internal class ImageExtractService : IImageExtractService
{
public IEnumerable<string> ExtractAllImageAddress(HtmlDocument doc)
{
const string mstring = @".+\.(jpg|png|ico|jpeg|bmp|tif)$";
var hrefList = doc.DocumentNode.SelectNodes(@".//*[@href]");
var srcList = doc.DocumentNode.SelectNodes(@".//*[@src]");
if (hrefList != null)
{
foreach (var href in hrefList)
{
var attr = href.Attributes["href"];
if (Regex.IsMatch(attr.Value, mstring))
{
yield return attr.Value;
}
}
}
if (srcList == null) yield break;
foreach (var src in srcList)
{
var attr = src.Attributes["src"];
if (Regex.IsMatch(attr.Value, mstring))
{
yield return attr.Value;
}
}
}
}
问题是,在执行命令后,应用程序将暂停。此时主线程正在
中运行System.Reactive.dll!System.Reactive.Concurrency.AsyncLock.Wait
但是没有抛出异常,如果允许继续,应用程序将退出。我试图引用/取消引用几行,而这似乎只是&#39;线程关联性的另一个实例。问题。但我不知道如何解决这个问题。简而言之,我的问题是:
更新
我尝试了一些没有observables的其他方法
public MainViewModel()
{
var canSearch =
this.WhenAnyValue(x => x.TargetUrl, targetWebSite => !string.IsNullOrEmpty(targetWebSite));
SearchCommand = ReactiveCommand.CreateFromTask(SearchImageAsync, canSearch, ThreadPoolScheduler.Instance);
}
和
private async Task SearchImageAsync()
{
var doc = await HtmlDownloadService.GetHtmlDocument(TargetUrl);
var imgs = ImageExtractService.ExtractAllImageAddress(doc);
foreach (var url in imgs)
{
ImageList.Add(new ScrappedWebImageViewModel {ImageUrl = url});
}
}
但仍然无法解决它。我使用的是最新的不稳定(alpha / preview)版本的Rx.Net&amp; RxUI,我开始使用的示例代码很少。所以,如果有人能提供一些,那将是一个巨大的帮助,谢谢!
答案 0 :(得分:2)
更改
_imageSequence.Subscribe(
到
_imageSequence.ObserveOn(RxApp.MainThreadScheduler).Subscribe(