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

时间:2014-09-25 14:13:44

标签: c# wpf drop-down-menu combobox

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

出于性能原因,我不想继续拨打System.IO.Ports.SerialPort.GetPortNames(),而只是在用户点击Combobox时调用它?这可能吗?是否存在针对此问题的MVVM方法?

4 个答案:

答案 0 :(得分:8)

使用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评论的那样。

答案 1 :(得分:0)

您可以使用类似MVVMLight的EventToCommand来完成此任务。基本上,单击组合的事件将挂钩到您的MVVM命令绑定,然后它将触发调用GetPortNames()的方法。

以下是一些替代方案:

MVVM Light: Adding EventToCommand in XAML without Blend, easier way or snippet?(查看接受的答案)

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

答案 2 :(得分:0)

我建议删除“仅限点击更新”的想法,并为此使用绑定和通知(除非出于某种原因,您认为会有如此多的连接/断开事件,这会降低您的系统速度)。最简单的版本是依赖属性。

在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 ComboBox在事件发生时更新。

答案 3 :(得分:0)

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

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

    }
}