我正试图与ReactiveUI
交流。我使用以下主要软件包创建了一个新项目:
该项目有一个page
和关联的viewmodel
。我想使用ReactiveUI
将视图与ViewModel绑定。但是绑定不起作用。项目将生成并运行,但不会触发任何property changed notification
也不会触发任何command
。该应用需要显示list
中的company names
。但是该列表不显示ViewModel
中定义的集合。该应用程序应允许用户在搜索CollectionChangeCommand
中进行每次更改后,使用query
对列表进行排序。
查看代码:
<rxui:ReactiveContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
xmlns:local="clr-namespace:Demo"
x:TypeArguments="local:MainViewModel"
x:Class="Demo.MainPage">
<Shell.TitleView>
<SearchBar x:Name="SearchHandler"
Placeholder="SelectCompany" />
</Shell.TitleView>
<StackLayout>
<ListView x:Name="CompaniesListView"
ItemsSource="{Binding Companies}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<StackLayout Orientation="Horizontal"
Margin="10">
<Label x:Name="NameLabel"
Text="{Binding Name}" />
</StackLayout>
<BoxView HorizontalOptions="FillAndExpand"
HeightRequest="1"
Color="BlueViolet" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="ClickMe"
x:Name="OnlyButton" />
</StackLayout>
</rxui:ReactiveContentPage>
背后的代码:
public partial class MainPage : ReactiveContentPage<MainViewModel>
{
MainViewModel vm;
public MainPage()
{
InitializeComponent();
this.Bind(ViewModel, vm => vm.Query, v => v.SearchHandler.Text);
this.BindCommand(ViewModel, vm => vm.ButtonClickedCommand, v => v.OnlyButton);
}
}
ViewModel代码:
[AddINotifyPropertyChangedInterface]
public class MainViewModel : ReactiveObject
{
public ObservableCollection<Company> Companies { get; private set; }
public ReactiveCommand<Unit, Unit> ButtonClickedCommand { get; set; }
public ReactiveCommand<Unit, Unit> CollectionChange { get; set; }
public string Query { get; set; }
public MainViewModel()
{
Companies = new ObservableCollection<Company>
{
new Company{Name="EPF CORPORATION"},
new Company{Name="ABC COMPANY PVT. LTD."},
new Company{Name="UNIQUE COMPUTER SYSTEMS"},
new Company{Name="MICROSOFT PRIVATE LIMITED"},
};
this.WhenAny(x => x.Query, x => !string.IsNullOrWhiteSpace(x.Value));
CollectionChange = ReactiveCommand.CreateFromTask(async () => await SortCollection());
ButtonClickedCommand = ReactiveCommand.CreateFromTask(async () => await ButtonClicked());
async Task SortCollection()
{
ObservableCollection<Company> temp;
temp = new ObservableCollection<Company>(Companies.OrderByDescending(m => m.Name.ToLower().StartsWith(Query.ToLower(), StringComparison.CurrentCulture)));
Companies.Clear();
foreach (Company c in temp)
Companies.Add(c);
}
async Task ButtonClicked()
{
await Shell.Current.DisplayAlert("Button Clicked", "The reactive button command fired finally", "OK");
}
}
我只想使用ReactiveObject
和ReactiveCommand
。我将坚持使用Xamarin.Forms Shell,直到ReactiveShell
不可用为止。
我将感谢任何可以向我展示如何与xamarin.forms一起正确使用ReactiveUI的人。
答案 0 :(得分:0)
在MainPage.xaml.cs中,您似乎从未创建过ViewModel?
您在ReactiveObject上使用INotifyPropertyChanged样式,那里有一个ReactiveUI样式。您不应在ReactiveObject上生成INotifyPropertyChange混合。
您有一个vm
属性,但也没有创建。
在ReactiveContentControl<TViewModel>
上,它具有一个名为ViewModel
的属性,您需要对其进行设置。可以从另一个控件中传入。
在您的ViewModel.cs
文件中,您还有一个this.WhenAny
,但似乎对生成的可观察物没有任何作用?
还请注意,一种更好的排序方法可能是使用DynamicData框架,该框架现在是ReactiveUI系列的一部分。
您可以做类似的事情
ViewModel.cs:
public class MainViewModel : ReactiveObject
{
private readonly SourceList<Company> _companies;
private readonly ReadOnlyObservableCollection<Company> _sortedCompanies;
//Reactive Commands
public ReactiveCommand<Unit, Unit> ButtonClickedCommand { get; }
public ReadOnlyObservableCollection<Company> Companies => _sortedCompanies;
[Reactive]
public string Query { get; set; }
public MainViewModel()
{
_companies = new SourceList<Company>();
_companies.AddRange(new[]
{
new Company{Name="EPF CORPORATION"},
new Company{Name="ABC COMPANY PVT. LTD."},
new Company{Name="UNIQUE COMPUTER SYSTEMS"},
new Company{Name="MICROSOFT PRIVATE LIMITED"},
});
// Delay to once every 500 milliseconds doing an update.
var refreshObs = this.WhenAnyValue(x => x.Query).Throttle(TimeSpan.FromMilliseconds(500));
_companies.Connect()
.AutoRefreshOnObservable(_ => refreshObs)
.Filter(m => Query == null || m.Name.IndexOf(Query, StringComparison.CurrentCultureIgnoreCase) >= 0) // If it contains a portion of the text.
.Sort(SortExpressionComparer<Company>.Ascending(t => t.Name))
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(out _sortedCompanies)
.Subscribe();
ButtonClickedCommand = ReactiveCommand.CreateFromTask(async () => await ButtonClicked());
}
async Task ButtonClicked()
{
await Shell.Current.DisplayAlert("Button Clicked", "The reactive button command fired finally", "OK");
}
}
MainPage.xaml.cs
public partial class MainPage : ReactiveContentPage<MainViewModel>
{
public MainPage()
{
InitializeComponent();
ViewModel = new MainViewModel();
//ReactiveUI Bindings
this.Bind(ViewModel, vm => vm.Query, v => v.SearchHandler.Text);
this.BindCommand(ViewModel, vm => vm.ButtonClickedCommand, v => v.OnlyButton);
this.OneWayBind(ViewModel, vm => vm.Companies, view => view.CompaniesListView.ItemsSource);
}
}
我在FodyWeavers.xml中添加了包含ReactiveUI
的ReactiveUI.Fody包
我也将您的ListView更改为不进行XAML绑定,所以<ListView x:Name="CompaniesListView">
这似乎对我来说很好。