使用ReactiveUI和Windows窗体绑定到ComboBox

时间:2015-12-17 14:01:05

标签: winforms mvvm binding reactiveui

我想使用ReactiveUI将我的viewmodel中的属性绑定到Windows窗体应用程序中的ComboBox。

我在WPF中找到了几个示例,但没有使用Windows窗体的示例。

编辑: 第1部分:将所选值绑定到 以下评论示例:

this.Bind(ViewModel, vm => vm.ViewModelProperty, v => v.comboBox.SelectedValue, comboBox.Events().SelectedValueChanged);

我收到错误:CS1955 Non-invocable member 'Component.Events' cannot be used like a method.

第2部分:将ComboBox中的项目绑定到viewmodel中的集合 ?不知道怎么做

5 个答案:

答案 0 :(得分:4)

首先,您的视图应该实现IViewFor<YourViewModel>接口然后

this.Bind(ViewModel, vm => vm.PropertyToBind, x => comboBox.SelectedValue, comboBox.Events().SelectedValueChanged) 

修改: 我创建了一个演示项目:

using System;
using System.Reactive.Linq;
using System.Windows.Forms;
using ReactiveUI;

namespace WindowsFormsApplication
{
    public partial class Form1 : Form, IViewFor<MyViewModel>
    {
        public Form1()
        {
            InitializeComponent();

            ViewModel = new MyViewModel();
            comboBox1.DataSource = ViewModel.Items;

            var selectionChanged = Observable.FromEvent<EventHandler, EventArgs>(
                h => (_, e) => h(e),
                ev => comboBox1.SelectedIndexChanged += ev,
                ev => comboBox1.SelectedIndexChanged += ev);
            this.Bind(ViewModel, vm => vm.SelectedItem, x => x.comboBox1.SelectedItem, selectionChanged);
        }

        public MyViewModel ViewModel { get; set; }

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

    public class MyItem
    {
        private readonly string _text;

        public MyItem(string text)
        {
            _text = text;
        }

        public override string ToString()
        {
            return _text;
        }
    }

    public class MyViewModel : ReactiveObject
    {
        private MyItem _selectedItem;

        public MyViewModel()
        {
            Items = new ReactiveList<MyItem> {new MyItem("test1"), new MyItem("test2")};
        }

        public MyItem SelectedItem
        {
            get { return _selectedItem; }
            set { this.RaiseAndSetIfChanged(ref _selectedItem, value); }
        }

        public ReactiveList<MyItem> Items { get; private set; }
    }
}

答案 1 :(得分:2)

您可以使用Observable.FromEventPattern方法将SelectedIndexChanged事件的触发绑定到您的视图模型属性。

comboBoxWithItems.DataSource = ViewModel.ListOfPossibleItemsProperty;
comboBoxWithItems.DisplayMember = "Name";

Observable.FromEventPattern<EventHandler, EventArgs>(
    ev => comboBoxWithItems.SelectedIndexChanged += ev,
    ev => comboBoxWithItems.SelectedIndexChanged -= ev)
    .Select(x => comboBoxWithItems.SelectedItem)
    .BindTo(this, x => x.ViewModel.SelectedItemProperty);

答案 2 :(得分:0)

您的初始vm.SelectedItem为null,并且尚未从视图更新VM。 在VM构造函数中设置初始选择。

答案 3 :(得分:0)

有关价值清单的一些改进意见:

  1. comboBox1.DataSource = ViewModel.Items;的直接集合替换为绑定OneWayBind(ViewModel, vm => vm.Items, v => v.comboBox1.DataSource);,以便ViewModel在视图构造函数中不存在,ViewModel可以是ReactiveBindingList动态改变。
  2. 使用ReactiveList代替{{1}},以便WinForms绑定可以对值列表中的更改做出反应(虽然我没有尝试过这种情况)。

答案 4 :(得分:0)

由于其他解决方案在UWP应用程序中对我不起作用,因此有一种正确的方法在WinForms,WPF和UWP应用程序中起作用:在视图的构造函数中使用Bind方法。 WPF / UWP的示例:

using ReactiveUI;
using System.Reactive.Disposables;

    public sealed partial class MyView : Page, IViewFor<MyViewModel>
    {

        public MyView()
        {
            InitializeComponent();

            this.WhenActivated(d =>
            {
                this.OneWayBind(ViewModel, vm => vm.Items, v => v.DropDownControl.ItemsSource)
                    .DisposeWith(d);

                this.Bind(ViewModel, vm => vm.SelectedItem, v => v.DropDownControl.SelectedItem)
                    .DisposeWith(d);
            });
        }


        public MyViewModel ViewModel
        {
            get => DataContext as MyViewModel;
            set => DataContext = value;
        }

        object IViewFor.ViewModel
        {
            get => ViewModel;
            set => ViewModel = value as MyViewModel;
        }
    }

在ViewModel中:

using ReactiveUI.Fody.Helpers;

    public sealed class MyViewModel : ReactiveObject
    {
        public void MyViewModel()
        {
            // Todo: Load items
        }

        [Reactive] public IList<MyItem> Items { get; set; } = new List<MyItem>();
        [Reactive] public MyItem? SelectedItem { get; set; }
    }