使用ReactiveUI和Windows Forms绑定到ComboBox

5
我希望能够在Windows Forms应用程序中,使用ReactiveUI将我的视图模型中的属性绑定到ComboBox上。我找到了几个WPF的例子,但没有Windows Forms的例子。
编辑: 第一部分:将选定的值绑定到 以下是从评论中提供的示例:
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.

第二部分:将ComboBox中的项目绑定到视图模型中的一个集合中 ?不知道如何操作

5个回答

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; }
    }
}

谢谢,伙计。当我尝试这样做时,出现了一个错误...我错过了什么?(请参见更新的问题) - AIDANDan
安装包反应式用户界面事件窗体。 - ds-b
再次感谢,但是这个包似乎不是ReactiveUI的一部分...我只能使用核心团队维护的包。有没有办法使用核心团队发布的包来实现这个? - AIDANDan
1
如果您不想使用 reactiveui-events-winforms 包,您可以将 comboBox.Events().SelectedValueChanged 替换为 Observable.FromEvent<EventHandler, EventArgs>( ev => comboBox.SelectedValueChanged += ev, ev => comboBox.SelectedValueChanged += ev); - ds-b
+1 谢谢。当我更改选择时(绑定发生),这似乎有效,但当应用程序启动时,绑定不会发生,组合框为空(而不是选择第一个项目)。有什么想法吗? - AIDANDan

3
您可以使用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);

0

你的初始vm.SelectedItem为null,且尚未有更改以从视图更新VM。 在VM构造函数中设置一个初始选择。


0

关于值列表的改进,以下是一些想法:

  1. 使用绑定 OneWayBind(ViewModel, vm => vm.Items, v => v.comboBox1.DataSource); 替换直接设置 comboBox1.DataSource = ViewModel.Items;,这样就不需要在视图构造函数中存在 ViewModel,并且可以动态更改 ViewModel
  2. 使用 ReactiveBindingList 替代 ReactiveList,以便 WinForms 绑定可以对值列表中的更改做出反应(尽管我没有为此确切场景尝试过)。

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; }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接