只是为了解决这个问题 - 我是XAML,Univeral Apps和ReactiveUI的完全新手,所以我可能在这里错过了一些简单的东西。
要获得ReactiveUI的句柄,我想我会尝试将文档(Reactive UI 101)中的ReactiveUI WPF Flickr示例移植到Windows Universal App。我正在使用Visual Studio 2015,ReactiveUI 6.5和更新的Splat。
我复制了代码并进行了必要的更改,以便为UWP编译。当前代码确实编译并打开,但无法正常工作。
我有两个问题:
我必须在“搜索:”框外单击以启动Flickr照片搜索。从我的理解,我不应该点击,它应该只是拿起我输入的东西,并在800ms的超时后启动搜索。调试照片搜索确实有效,并且我的SearchResults将返回一组对象。
第二个问题是即使我得到结果列表,也从不填充ListBox。我已尝试使用示例中所示的Binding,并使用x:Bind,因为我学习了如何在所有UWP教程中做 - 没有骰子。
我下载了另一个UWP示例(RxUI and UWP .Net Native Sample),我正在研究它的结构和设置,看看我错过了什么,但现在对我来说有点复杂。
如果有人能指出我正确的方向,那将会有很大的帮助。
这是我的XAML:
<Page
x:Class="ReactiveUIFlickerApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ReactiveUIFlickerApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:ReactiveUIFlickerApp.Models"
x:Name="MainPageView"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="PhotoDataTemplate"
x:DataType="data:FlickrPhoto">
<Grid MaxHeight="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{x:Bind Url, Mode=OneWay}" Margin="6" MaxWidth="128"
HorizontalAlignment="Center" VerticalAlignment="Center" />
<StackPanel Grid.Column="1" Margin="6">
<TextBlock FontSize="14" FontWeight="Bold" Text="{x:Bind Title}" />
<TextBlock FontStyle="Italic" Text="{x:Bind Description}"
TextWrapping="Wrap" Margin="6" />
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Margin="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock FontSize="16"
FontWeight="Bold"
VerticalAlignment="Center">Search For:</TextBlock>
<TextBox Grid.Column="1"
Margin="6,0,0,0"
Text="{x:Bind PageViewModel.SearchTerm, Mode=TwoWay}"/>
<TextBlock Grid.Column="2"
Margin="6,0,0,0"
FontSize="16"
FontWeight="Bold"
Text="..."
Visibility="{x:Bind PageViewModel.SpinnerVisibility}" />
<ListBox Grid.ColumnSpan="3"
Grid.Row="1"
Margin="0,6,0,0"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{x:Bind PageViewModel.SearchResults, Mode=OneWay}"
ItemTemplate="{StaticResource PhotoDataTemplate}" />
</Grid>
XAML代码隐藏:
public sealed partial class MainPage : Page
{
public MainPageViewModel PageViewModel { get; private set;}
public MainPage()
{
PageViewModel = new MainPageViewModel();
this.InitializeComponent();
}
}
MainPageViewModel(在解决方案中自己的View文件夹中):
public class MainPageViewModel : ReactiveObject
{
string _SearchTerm;
public string SearchTerm
{
get { return _SearchTerm; }
set { this.RaiseAndSetIfChanged(ref _SearchTerm, value); }
}
public ReactiveCommand<List<FlickrPhoto>> ExecuteSearch { get; protected set; }
ObservableAsPropertyHelper<List<FlickrPhoto>> _SearchResults;
public List<FlickrPhoto> SearchResults => _SearchResults.Value;
ObservableAsPropertyHelper<Visibility> _SpinnerVisibility;
public Visibility SpinnerVisibility => _SpinnerVisibility.Value;
public MainPageViewModel()
{
ExecuteSearch =
ReactiveCommand.CreateAsyncTask(parameter => GetSearchResultsFromFlickr(this.SearchTerm));
this.WhenAnyValue(x => x.SearchTerm)
.Throttle(TimeSpan.FromMilliseconds(800), RxApp.MainThreadScheduler)
.Select(x => x?.Trim()) // null conditional operator
.DistinctUntilChanged()
.Where(x => !String.IsNullOrWhiteSpace(x))
.InvokeCommand(ExecuteSearch);
_SpinnerVisibility = ExecuteSearch.IsExecuting
.Select(x => x ? Visibility.Visible : Visibility.Collapsed)
.ToProperty(this, x => x.SpinnerVisibility, Visibility.Collapsed/*Hidden*/);
ExecuteSearch.ThrownExceptions.Subscribe(ex => { Debug.WriteLine(ex.ToString());/* Handle errors here */});
_SearchResults = ExecuteSearch.ToProperty(this, x => x.SearchResults, new List<FlickrPhoto>());
}
public static async Task<List<FlickrPhoto>> GetSearchResultsFromFlickr(string searchTerm)
{
var client = new HttpClient();
var stream = await client.GetStreamAsync(String.Format(CultureInfo.InvariantCulture,
"http://api.flickr.com/services/feeds/photos_public.gne?tags={0}&format=rss_200",
WebUtility.UrlEncode(searchTerm)));
//var doc = await Task.Run(() => XDocument.Load(String.Format(CultureInfo.InvariantCulture,
// "http://api.flickr.com/services/feeds/photos_public.gne?tags={0}&format=rss_200",
// WebUtility.UrlEncode(searchTerm))));
var doc = await Task.Run( () => XDocument.Load(stream) );
if (doc.Root == null)
return null;
var titles = doc.Root.Descendants("{http://search.yahoo.com/mrss/}title")
.Select(x => x.Value);
var tagRegex = new Regex("<[^>]+>", RegexOptions.IgnoreCase);
var descriptions = doc.Root.Descendants("{http://search.yahoo.com/mrss/}description")
.Select(x => tagRegex.Replace(WebUtility.HtmlDecode(x.Value), ""));
//.Select(x => tagRegex.Replace(HttpUtility.HtmlDecode(x.Value), ""));
var items = titles.Zip(descriptions,
(t, d) => new FlickrPhoto { Title = t, Description = d }).ToArray();
var urls = doc.Root.Descendants("{http://search.yahoo.com/mrss/}thumbnail")
.Select(x => x.Attributes("url").First().Value);
var ret = items.Zip(urls, (item, url) => { item.Url = url; return item; }).ToList();
return ret;
}
}
答案 0 :(得分:0)
正如我在回复your issue on Github时提到的,UWP在控件失去焦点之前不会更新TextBox
绑定。您必须使用RxUI Bind
系列来解决这个问题。
至于结果列表,我不是完全确定为什么它不起作用,除了我将绑定到ReactiveList<T>
(或更可能,{{1} })。这样,IReadOnlyReactiveList<T>
将List<T>
使用ListBox.ItemsSource
,而不是销毁ReactiveList<T>
所绑定的INotifyPropertyChanged
。
一旦你开始工作,尝试将列表填充代码移动到ReactiveCommand
工作者的主体中,这通常会更好。