WPF MVVM-单击时更新下拉列表



我有一个下拉列表(ComboBox),显示机器上所有可用的com端口。现在,当您连接和断开设备时,端口会来来去去。

出于性能原因,我不想一直调用System.IO.Ports.SerialPort.GetPortNames(),而是在用户单击组合框时调用它?这可能吗?是否有MVVM方法来解决此问题?

使用InvokeCommandAction

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

DropDownOpenedCommand是ViewModel上的ICommand属性。

<ComboBox>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="DropDownOpened">
            <i:InvokeCommandAction Command="{Binding DropDownOpenedCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>

编辑:显然DropDownOpened没有SelectionChanged,正如Patrice评论的那样。

您可以使用类似MVVMLight的EventToCommand之类的东西来实现这一点。基本上,单击组合框的事件将挂接到MVVM命令绑定,然后它将触发调用GetPortNames()的方法。

以下是一些替代方案:

MVVM Light:在没有Blend的XAML中添加EventToCommand,更简单的方法还是代码片段?(检查接受的答案)

http://www.danharman.net/2011/08/05/binding-wpf-events-to-mvvm-viewmodel-commands/(棱镜)

我建议取消"只在点击时更新"的想法,只使用绑定和通知(除非出于某种原因,你认为会有太多连接/断开连接事件,这会减慢你的系统速度)。最简单的版本是依赖属性。

在ViewModel上提供IObservableList<Port>属性作为依赖属性,如下所示:

    /// <summary>
    /// Gets or sets...
    /// </summary>
    public IObservableList<Port> Ports
    {
        get { return (IObservableList<Port>)GetValue(PortsProperty); }
        set { SetValue(PortsProperty, value); }
    }
    public static readonly DependencyProperty PortsProperty = DependencyProperty.Register("Ports", typeof(IObservableList<Port>), typeof(MyViewModelClass), new PropertyMetadata(new ObservableList<Port>));

现在,无论何时连接或断开设备,您都可以在该列表中添加/删除项目,只是不要替换该列表。这将强制列表为列表上的每个操作发送一个ListChangedEvent,ComboBox(或任何其他绑定的UI)将对这些事件做出反应。

这对你来说应该足够高性能,因为这只会导致UI组合框在事件发生时更新。

我尝试将事件路由到一个命令:

XAML:

<ComboBox 
    ItemsSource="{Binding Items}" 
    local:ControlBehavior.Event="SelectionChanged"
    local:ControlBehavior.Command="{Binding Update}" />

代码:

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
namespace StackOverflow
{
    public class ControlBehavior
    {
        public static DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(ControlBehavior));
        public static DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ControlBehavior));
        public static DependencyProperty EventProperty = DependencyProperty.RegisterAttached("Event", typeof(string), typeof(ControlBehavior), new PropertyMetadata(PropertyChangedCallback));
        public static void EventHandler(object sender, EventArgs e)
        {
            var s = (sender as DependencyObject);
            if (s != null)
            {
                var c = (ICommand)s.GetValue(CommandProperty);
                var p = s.GetValue(CommandParameterProperty);
                if (c != null && c.CanExecute(s))
                    c.Execute(s);
            }
        }
        public static void PropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs a)
        {
            if (a.Property == EventProperty)
            {
                EventInfo ev = o.GetType().GetEvent((string)a.NewValue);
                if (ev != null)
                {
                    var del = Delegate.CreateDelegate(ev.EventHandlerType, typeof(ControlBehavior).GetMethod("EventHandler"));
                    ev.AddEventHandler(o, del);
                }
            }
        }
        public string GetEvent(UIElement element)
        {
            return (string)element.GetValue(EventProperty); 
        }
        public static void SetEvent(UIElement element, string value)
        {
            element.SetValue(EventProperty, value);
        }
        public ICommand GetCommand(UIElement element)
        {
            return (ICommand)element.GetValue(CommandProperty);
        }
        public static void SetCommand(UIElement element, ICommand value)
        {
            element.SetValue(CommandProperty, value);
        }
        public object GetCommandParameter(UIElement element)
        {
            return element.GetValue(CommandParameterProperty);
        }
        public static void SetCommandParameter(UIElement element, object value)
        {
            element.SetValue(CommandParameterProperty, value);
        }
    }
}

最新更新