ReactiveUI版本9.19.5绑定不适用于Xamarin.Forms版本4.1.0

时间:2019-07-26 07:44:28

标签: xamarin.forms reactiveui

我正试图与ReactiveUI交流。我使用以下主要软件包创建了一个新项目:

  1. Xamarin.Forms 4.1.0.618606
  2. PropertyChanged.Fody 3.0.1
  3. ReactiveUI 9.19.5
  4. 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");
        }
    }

我只想使用ReactiveObjectReactiveCommand。我将坚持使用Xamarin.Forms Shell,直到ReactiveShell不可用为止。

我将感谢任何可以向我展示如何与xamarin.forms一起正确使用ReactiveUI的人。

1 个答案:

答案 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">

这似乎对我来说很好。