我正在使用Visual Studio 2017 Communitiy版本/ .NET Framework 4.6.1 / WPF。顺便说一句。我使用MVVM。
我的目标是在 Combobox 中显示所有可用的串行端口。我已经实现了这个,但是现在我想在打开Dropdow菜单或连接新设备时自动更新Combobox。因此,我需要一些属性才能Binding
到我的ViewModel
。
在MSDN上我找到了对我来说听起来不错的Combobox.DroppedDown-Property,但是我无法使用它,找不到DroppedDown ...(System.Windows.Forms
是正确的参考?)。
您是否发现了我的错误,或者您是否有更好的解决方案?
谢谢!
<UserControl x:Class="HC_SR04_MPU6050.View.SerialView_MPU_6050"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:HC_SR04_MPU6050.View"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="MPU-6050" HorizontalAlignment="Center"/>
<Label Grid.Row="0" Grid.Column="3" Content="Y-ROT[°]" HorizontalAlignment="Center"/>
<Button Command="{Binding Connect_Clicked}" Grid.Row="1" Grid.Column="0" Content="Connect" Height="20" Width="60" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="6" ToolTip="Opens/Connects the selected COM-PORT"/>
<Button Command="{Binding Measure_Clicked}" Grid.Row="1" Grid.Column="1" Content="MEASURE" Height="20" Width="60" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="6" ToolTip="Starts the Measurement routine"/>
<Button Command="{Binding Stop_Clicked}" Grid.Row="1" Grid.Column="2" Content="STOP" Height="20" Width="60" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="6" ToolTip="Stops the communication/ Closes/Disconnects the selected COM-PORT"/>
<Label Content="{Binding Rotation.Y_Rotation}" Grid.Row="1" Grid.Column="3" Height="25" Width="50" Margin="6" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="1" BorderBrush="Black" ToolTip="Output from Arduino/HC-SR04" VerticalContentAlignment="Center" FontSize="11"/>
<ComboBox Grid.Column="4" Grid.Row="1" Width="62" Height="25" Margin="6" Text="{Binding Rotation.Port_Name}" ItemsSource="{Binding Rotation.AvailablePorts}"/>
</Grid>
</UserControl>
答案 0 :(得分:1)
您还可以查看互动触发器是否可以为您提供帮助。
只需在用户控件打开标记中输入类似内容:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
然后在你的组合框标签内放置:
<i.Interaction.Triggers>
<i:EventTrigger EventName="DropDownOpened">
<i:InvokeCommandAction Command="{Binding UpdateComnListCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
这样,每次下拉打开时,都会调用UpdateCommListCommand。
您可能会遇到一些难以解决的问题。我不确定列表更新是否会在实际显示打开的组合框之前触发。
答案 1 :(得分:0)
我没有看到你在哪里设置ViewModel所以我会假设它在代码背后。 (我个人也喜欢在XAML中设置它,并且从不接触MVVM中的代码,但这与此无关。)
如果您正在使用ViewModel进行绑定,那么ViewModel负责翻译您希望视图做出反应的任何内容并通知侦听视图。但是,业务/应用程序逻辑实际上并不存在于ViewModel中。我建议的可能是Singleton类,它会为您监听和传递端口。让它管理端口列表等。然后您的ViewModel可以监听该类并在设备连接时自行更新等。一旦ViewModel更新(如果连线正确),那么视图也应该更新。因此,解决了设备连接后您的视图更新...到目前为止超级简单。现在,当您单击ComboBox下拉列表时,让它也进行更新。
为了实现这一点,我们希望向ViewModel添加一个ICommand(我会以RelayCommand的形式执行此操作,您需要自己创建或尝试使用像SpeckyWPF nuget包这样的第三方版本。)
在ViewModel中有命令后,它指向用于更新串行端口的方法。
现在在视图中,当您单击ComboBox时,您有一个事件。我建议不要使用后面的代码,这可能看起来更容易,但是要创建一个AttachableProperty或自定义ComboBox控件,以便您可以将命令附加到此事件。 (还有第三方工具可以帮助您这样做。)
在所有情况下,您的ViewModel都会成为通知。您只需绑定到命令即可更新它并在需要时调用它,或者只是等待设备插入。除了添加命令和所有通知都在VM中之外,View本身不需要任何更改。它所属的类中的逻辑用于串行端口。
答案 2 :(得分:0)
当串口更改(添加/删除)时,您可以使用ManagementEventWatcher
对象启动事件。
ManagementEventWatcher
位于System.Management
库中。
例如在ViewModel
中using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Management;
public class ViewModel
{
private ManagementEventWatcher _watcher;
public ViewModel()
{
WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent");
_watcher = new ManagementEventWatcher(query);
_watcher.EventArrived += (s, e) => RefreshPortNames();
_watcher.Start();
}
public ObservableCollection<string> PortNames { get; } = new ObservableCollection<string>(SerialPort.GetPortNames());
private void RefreshPortNames()
{
// The `ManagementEventWatcher.EventArrived` event is fired from a different thread than the UI thread
// so we need to return to UI thread to manipulate the `PortNames` property.
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
PortNames.Clear();
foreach (string portName in SerialPort.GetPortNames())
{
PortNames.Add(portName);
}
});
}
//TODO: Dispose `_watcher` object if this `ViewModel` is short-lived.
}
然后您只需像往常一样将PortNames
属性绑定到ComboBox.ItemsSource
。
<ComboBox ItemsSource="{Binding PortNames}" />