1
votes

I have a simple ViewModel:

public class SampleCollectionViewModel : ReactiveObject
    {
        public SampleCollectionViewModel()
        {
            this.Countries = new ReactiveList<Country>();
            this.Countries.Add(new Country { Name = "Andora" });
            this.Countries.Add(new Country { Name = "Aruba" });
            this.Countries.Add(new Country { Name = "Afganistan" });
            this.Countries.Add(new Country { Name = "Algeria" });
            this.Countries.Add(new Country { Name = "Argentina" });
            this.Countries.Add(new Country { Name = "Armenia" });
            this.Countries.Add(new Country { Name = "Antigua" });    
            //CountryNames.AddRange(this.Countries.Select(x => x.Name));
        }

        public ReactiveList<Country> Countries { get; set; }
        //public ReactiveList<string> CountryNames { get; set; }
    }

and a simple View:

public partial class SampleCollectionWindow : Window, IViewFor<SampleCollectionViewModel>
    {
        public SampleCollectionWindow()
        {
            InitializeComponent();

            this.ViewModel = new SampleCollectionViewModel();


            this.Bind(ViewModel, vm => vm.Countries, v => v.CountriesListBox.ItemsSource);
        }

        public SampleCollectionViewModel ViewModel { get; set; }

        object IViewFor.ViewModel
        {
            get { return ViewModel; }
            set { ViewModel = (SampleCollectionViewModel)value; }
        }
    }

When I run it I get: exception Additional information: Can't two-way convert between ReactiveUI.ReactiveList``1[DemoReactiveUiWpf.SampleCollection.Country] and System.Collections.IEnumerable. To fix this, register a IBindingTypeConverter

If I change this.Bind(ViewModel, vm => vm.Countries, v => v.CountriesListBox.ItemsSource); to this.OneWayBind(ViewModel, vm => vm.Countries, v => v.CountriesListBox.ItemsSource); nothing happens with ListBox

Later I'm going to expand this simple demo to have a command and async command to add new country to the model.

Remove selected in ListBox / ListView items.

Try filtering, sorting and other interesting operations that ReactiveUI offers.

But as for now I just can't do simple binding...

How to bind ListBox / ListView to ReactiveList<Country> and do common operations with ReactiveList + ListBox/ListView in the right way?

Thank you!

1

1 Answers

4
votes

You definitely cannot use a two-way binding to bind to ItemsSource - as the error message says, you can't guarantee that someone setting ListBox.ItemsSource will use a ReactiveList<Country>. This works on my machine:

this.OneWayBind(ViewModel, x => x.Countries, x => x.countries.ItemsSource);

...nothing happens with ListBox

I wonder if you perhaps didn't configure a DataTemplate? ReactiveUI overrides default DataTemplates with one that uses ViewModelViewHost (and since you most likely don't have a View registered for Country, it would fail).

Update: Here's how I'd bind SelectedItems, put this in the View:

this.WhenAnyValue(x => x.countries.SelectedItems)
    .Select(list => list.Cast<Country>())
    .BindTo(this, x => x.ViewModel.SelectedCountries);