应用场景: 我想把View层的一个布局控件和功能按钮传到ViewModel层,达到动态变更布局,同时灵活获取功能按钮的属性,让View和ViewModel完全分离,而不受View层影响。
最后我想到使用IMultiValueConverter实现多参传入ViewModel层来解决,不知道还有没有更好的办法?
基本原理:要将值转换器与 MultiBinding 关联,请创建一个实现 IMultiValueConverter 接口的类,然后实现 Convert 和 ConvertBack 方法。
集合中的各个绑定可以具有自己的值转换器。
使用 MultiBinding,您可以将绑定目标属性绑定到源属性列表,然后应用逻辑以使用给定的输入生成值。
步骤:
注意:返回的values一定要转为数组列表values.ToArray()
参考如下代码:
using System; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace TLAgent.SecurityManager.WPF.MultiBindings { public class DataConverter : IMultiValueConverter { #region IMultiValueConverter Members public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return values.ToArray() ; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } }
<Fluent:Button Header="添加用户" Icon="Images\Green.png" LargeIcon="Images\GreenLarge.png" x:Name="BtnAddUser" Command="{Binding AddUserCommand}"> <Fluent:Button.CommandParameter> <MultiBinding Converter="{ StaticResource ResourceKey=dataConverter}" Mode="TwoWay"> <MultiBinding.Bindings> <Binding ElementName="BtnAddUser"/> <Binding ElementName="dockManager "/> </MultiBinding.Bindings> </MultiBinding> </Fluent:Button.CommandParameter> </Fluent:Button>
<Window.Resources> <local:DataConverter x:Key="dataConverter"/> </Window.Resources>
注意:DelegateCommand<object[]>的参数是要支持对象数组。
using System; using System.Linq; using System.Reflection; using System.Windows; using System.Windows.Input; using Microsoft.Practices.Prism.Commands; using Microsoft.Practices.Prism.ViewModel; using Xceed.Wpf.AvalonDock; using Xceed.Wpf.AvalonDock.Layout; using Application = System.Windows.Application; using MessageBox = System.Windows.MessageBox; using UserControl = System.Windows.Controls.UserControl; namespace TLAgent.SecurityManager.WPF.ViewModels { public class MainWindowViewModel : NotificationObject { public ICommand ExitSystemCommand { get; set; } public ICommand AddUserCommand { get; set; } public ICommand OpenHelpCommand { get; set; } public MainWindowViewModel() { ExitSystemCommand = new DelegateCommand(this.OnExit); OpenHelpCommand = new DelegateCommand(this.OnOpenSupport); AddUserCommand = new DelegateCommand<object[]>(this.AddUser); } private void CreateTab(DockingManager dockManager, string tabName, UserControl control) { var firstDocumentPane = dockManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault(); if (firstDocumentPane != null) { LayoutDocument doc2 = new LayoutDocument(); doc2.Title = tabName; doc2.Content = control; doc2.IsActive = true; firstDocumentPane.Children.Add(doc2); } } private void OnExit() { MessageBoxResult result = MessageBox.Show("确定要退出系统吗?", "确认消息", MessageBoxButton.OKCancel, MessageBoxImage.Question); if (result == MessageBoxResult.OK) { Application.Current.Shutdown(); } } private void OnOpenSupport() { MessageBox.Show("帮助窗口!"); } private void AddUser(object[] objParam) { if (objParam.Length == 2) { Fluent.Button button = (Fluent.Button)objParam[0]; DockingManager dockingManager = (DockingManager)objParam[1]; UserControl control; control = new UserControl1(); CreateTab(dockingManager, button.Header.ToString(), control); } } } }
这样就可以在方法AddUer的参数中取得View层绑定的两个控件:
<MultiBinding.Bindings> <Binding ElementName="BtnAddUser"/> <Binding ElementName="dockManager "/> </MultiBinding.Bindings>
这样基本就实现了从View层传多个对象到ViewModel层了。