我有一个下拉列表(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);
}
}
}