使用 ReactiveUI 和 Windows 表单绑定到 ComboBox
Binding to ComboBox using ReactiveUI and Windows Forms
我想使用 ReactiveUI 将视图模型中的 属性 绑定到 Windows Forms 应用程序中的 ComboBox。
我找到了几个 WPF 示例,但没有找到 Windows Forms 示例。
编辑:
第 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 中的项目绑定到视图模型中的集合
?不知道怎么办
首先,您的视图应实现 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; }
}
}
您可以使用 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);
您的初始 vm.SelectedItem 为空,并且尚未从视图中更新 VM。
在 VM 构造函数中设置初始选择。
关于值列表的一些改进想法:
- 用绑定
OneWayBind(ViewModel, vm => vm.Items, v => v.comboBox1.DataSource);
替换 comboBox1.DataSource = ViewModel.Items;
的直接集,这样 ViewModel
就没有必要存在于视图构造函数中,并且 ViewModel
可以动态更改。
- 使用
ReactiveBindingList
而不是 ReactiveList
以便 WinForms 绑定可以对值列表中的更改做出反应(尽管我还没有针对这个确切的场景尝试过)。
由于其他解决方案在 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;
}
}
在视图模型中:
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; }
}
我想使用 ReactiveUI 将视图模型中的 属性 绑定到 Windows Forms 应用程序中的 ComboBox。
我找到了几个 WPF 示例,但没有找到 Windows Forms 示例。
编辑: 第 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 中的项目绑定到视图模型中的集合 ?不知道怎么办
首先,您的视图应实现 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; }
}
}
您可以使用 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);
您的初始 vm.SelectedItem 为空,并且尚未从视图中更新 VM。 在 VM 构造函数中设置初始选择。
关于值列表的一些改进想法:
- 用绑定
OneWayBind(ViewModel, vm => vm.Items, v => v.comboBox1.DataSource);
替换comboBox1.DataSource = ViewModel.Items;
的直接集,这样ViewModel
就没有必要存在于视图构造函数中,并且ViewModel
可以动态更改。 - 使用
ReactiveBindingList
而不是ReactiveList
以便 WinForms 绑定可以对值列表中的更改做出反应(尽管我还没有针对这个确切的场景尝试过)。
由于其他解决方案在 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;
}
}
在视图模型中:
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; }
}