Winforms 使用ReactiveUI和Windows窗体绑定到ComboBox

Winforms 使用ReactiveUI和Windows窗体绑定到ComboBox,winforms,mvvm,binding,reactiveui,Winforms,Mvvm,Binding,Reactiveui,我想使用ReactiveUI将viewmodel中的属性绑定到Windows窗体应用程序中的组合框 我发现了几个WPF示例,但没有Windows窗体示例 编辑: 第1部分:将选定值绑定到 以下是评论中的示例: this.Bind(ViewModel, vm => vm.ViewModelProperty, v => v.comboBox.SelectedValue, comboBox.Events().SelectedValueChanged); 我得到错误:CS1955非可开票成

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

我发现了几个WPF示例,但没有Windows窗体示例

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

this.Bind(ViewModel, vm => vm.ViewModelProperty, v => v.comboBox.SelectedValue, comboBox.Events().SelectedValueChanged);
我得到错误:
CS1955非可开票成员“Component.Events”不能像方法一样使用。

第2部分:将组合框中的项绑定到viewmodel中的集合
? 如果不知道如何做,首先,您的视图应该为接口实现
iviewf,然后

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; }
    }
}
使用系统;
使用System.Reactive.Linq;
使用System.Windows.Forms;
使用ReactiveUI;
命名空间Windows窗体应用程序
{
公共部分类Form1:Form,IViewFor
{
公共表格1()
{
初始化组件();
ViewModel=新的MyViewModel();
comboBox1.DataSource=ViewModel.Items;
var selectionChanged=Observable.FromEvent(
h=>(u,e)=>h(e),
ev=>comboBox1.SelectedIndexChanged+=ev,
ev=>comboBox1.SelectedIndexChanged+=ev);
this.Bind(ViewModel,vm=>vm.SelectedItem,x=>x.comboBox1.SelectedItem,selectionChanged);
}
公共MyViewModel视图模型{get;set;}
对象IViewFor.ViewModel
{
获取{return ViewModel;}
设置{ViewModel=(MyViewModel)值;}
}
}
公共类MyItem
{
私有只读字符串\u文本;
公共MyItem(字符串文本)
{
_文本=文本;
}
公共重写字符串ToString()
{
返回文本;
}
}
公共类MyViewModel:反应对象
{
私人MyItem _selectedItem;
公共MyViewModel()
{
Items=newreactivelist{newmyitem(“test1”)、newmyitem(“test2”)};
}
公共MyItem SelectedItem
{
获取{return\u selectedItem;}
设置{this.RaiseAndSetIfChanged(ref _selectedItem,value);}
}
公共反应列表项{get;private set;}
}
}

您可以使用
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);
comboBoxWithItems.DataSource=ViewModel.ListOfPossibleItemsProperty;
comboBoxWithItems.DisplayMember=“Name”;
可观察的。从事件模式(
ev=>comboBoxWithItems.SelectedIndexChanged+=ev,
ev=>comboBoxWithItems.SelectedIndexChanged-=ev)
.Select(x=>comboBoxWithItems.SelectedItem)
.BindTo(这个,x=>x.ViewModel.SelectedItemProperty);

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

与值列表相关的一些改进意见:

  • 替换
    comboBox1.DataSource=ViewModel.Items的直接集合带有绑定
    OneWayBind(ViewModel,vm=>vm.Items,v=>v.comboBox1.DataSource)
    这样就不必在视图构造函数中存在
    ViewModel
    ,并且可以动态更改
    ViewModel
  • 使用
    ReactiveBindingList
    而不是
    ReactiveList
    ,这样WinForms绑定就可以对值列表中的更改做出反应(尽管我还没有在这种情况下尝试过)

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

    使用ReactiveUI;
    使用系统反应性一次性用品;
    公共密封部分类MyView:第页,IViewFor
    {
    公共MyView()
    {
    初始化组件();
    当激活时(d=>
    {
    this.OneWayBind(ViewModel,vm=>vm.Items,v=>v.DropDownControl.ItemsSource)
    .处置(d);
    this.Bind(ViewModel,vm=>vm.SelectedItem,v=>v.DropDownControl.SelectedItem)
    .处置(d);
    });
    }
    公共MyViewModel视图模型
    {
    get=>DataContext作为MyViewModel;
    set=>DataContext=value;
    }
    对象IViewFor.ViewModel
    {
    get=>ViewModel;
    将=>ViewModel=值设置为MyViewModel;
    }
    }
    
    在ViewModel中:

    使用ReactiveUI.Fody.Helpers;
    公共密封类MyViewModel:ReactiveObject
    {
    public void MyViewModel()
    {
    //Todo:加载项目
    }
    [Reactive]公共IList项{get;set;}=new List();
    [被动]公共MyItem?选择EdItem{get;set;}
    }
    
    谢谢你,伙计。当我尝试这样做时,我会出错。。。我错过了什么?(请参阅更新的问题)
    安装包reactiveui事件winforms
    ;)再次感谢,但此软件包似乎不是ReactiveUI的一部分。。。我只能使用由核心团队维护的包。您知道如何使用核心团队发布的包实现这一点吗?如果您不想使用reactiveui events winforms包,您可以将
    comboBox.events().SelectedValueChanged
    替换为
    Observable.FromEvent>(ev=>comboBox.SelectedValueChanged+=ev,ev=>comboBox.SelectedValueChanged+=ev);
    +1谢谢。当我更改选择时(绑定发生),这似乎有效,但当应用程序启动时,绑定不会发生,并且组合框为空(而不是选择第一项)。有什么想法吗?