ReactiveUI 版本 9.19.5 绑定不适用于 Xamarin.Forms 版本 4.1.0
The ReactiveUI ver 9.19.5 Binding is not working with Xamarin.Forms ver 4.1.0
我正在努力了解 ReactiveUI
。我创建了一个包含以下主要包的新项目:
- Xamarin.Forms 4.1.0.618606
- PropertyChanged.Fody 3.0.1
- ReactiveUI 9.19.5
- ReactiveUI.XamForms 9.19.5
该项目有一个 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,我将不胜感激。
在您的 MainPage.xaml.cs 中,您似乎从未创建过 ViewModel?
您正在 ReactiveObject 上使用 INotifyPropertyChanged fody,那里有一个 ReactiveUI fody。您不应在 ReactiveObject 上生成混合 INotifyPropertyChange。
您有一个 vm
属性 但也没有创建。
在 ReactiveContentControl<TViewModel>
上有一个名为 ViewModel
的 属性,您需要对其进行设置。那可以从另一个控件传入。
同样在你的 ViewModel.cs
文件中你有一个 this.WhenAny
但似乎没有对生成的可观察对象做任何事情?
另请注意,更好的排序方法可能是使用现在属于 ReactiveUI 系列的 DynamicData 框架。
你可以这样做
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">
这对我来说似乎很有效。
我正在努力了解 ReactiveUI
。我创建了一个包含以下主要包的新项目:
- Xamarin.Forms 4.1.0.618606
- PropertyChanged.Fody 3.0.1
- ReactiveUI 9.19.5
- ReactiveUI.XamForms 9.19.5
该项目有一个 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,我将不胜感激。
在您的 MainPage.xaml.cs 中,您似乎从未创建过 ViewModel?
您正在 ReactiveObject 上使用 INotifyPropertyChanged fody,那里有一个 ReactiveUI fody。您不应在 ReactiveObject 上生成混合 INotifyPropertyChange。
您有一个 vm
属性 但也没有创建。
在 ReactiveContentControl<TViewModel>
上有一个名为 ViewModel
的 属性,您需要对其进行设置。那可以从另一个控件传入。
同样在你的 ViewModel.cs
文件中你有一个 this.WhenAny
但似乎没有对生成的可观察对象做任何事情?
另请注意,更好的排序方法可能是使用现在属于 ReactiveUI 系列的 DynamicData 框架。
你可以这样做
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">
这对我来说似乎很有效。