wpf - WPF MVVM 组合框 SelectedItem 无法正常工作
问题描述
我已经搜索并阅读了几篇文章,但我找不到我做错了什么。
我有一个带有ObservableCollection<string> Available_COMPorts
as的 ComboBox ItemsSource
。在SelectedValue
我绑定了一个名为的SelectedCOMPort
字符串Mode = TwoWay
。
<Label Content="Porta COM: "></Label>
<ComboBox ItemsSource="{Binding Available_COMPorts}"
SelectedValue="{Binding SelectedCOMPort, Mode=TwoWay}" />
在组合框之后,我有一个标签显示SelectedCOMPort
<Label Content="Status: " />
<Label Content="{Binding SelectedCOMPort}" Foreground="Red" />
我已经做了两者Available_COMPorts
和。在我的 ViewModel 初始化中,我用三个可用的 SerialPort 字符串(“COM6”、“COM5”、“COM4”)填充并设置(“COM6”)。SelectedCOMPort
INotifyPropertyChanged
Available_COMPorts
SelectedCOMPort = "Available_COMPorts[0]"
当我运行代码时,ComboBox 有三个项目,选中的项目是“COM6”,标签显示“COM6”(一切正常)。然后我选择“COM5”,标签将其值更新为“COM5”。这在以下图片中进行了介绍。
问题是当我尝试访问SelectedCOMPort
时ViewModel
,因为我需要选择的项目来连接我的 SerialPort。SelectedCOMPort
始终作为默认值“COM6” 。我尝试访问SelectedCOMPort
连接单击命令。
调试,在函数上使用断点INotifyProperty
我意识到绑定属性似乎工作正常,但是当它离开时,INotifyProperty
该值又恢复为默认值。
为什么会这样?我尝试了几种方法,但没有一个对我有用。
以下是带有 INotifyProperty 的 ViewModel 和 BaseViewModel:
BaseViewModel:INotifyPropertyChanged
public class BaseViewModel : INotifyPropertyChanged
{
#region PropertyChange
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
protected void SetProperty<T>(ref T backingField, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingField, value)) return;
backingField = value;
OnPropertyChanged(propertyName);
}
#endregion
}
视图模型
public class LiveGraphViewModel : BaseViewModel
{
public ConnectButtonCommand ConnectButtonCommand { get; set; }
private ObservableCollection<string> _availableCOMPorts;
private string _selectedCOMPort;
public ObservableCollection<string> Available_COMPorts
{
get { return _availableCOMPorts; }
set { SetProperty(ref _availableCOMPorts, value); }
}
public string SelectedCOMPort
{
get { return _selectedCOMPort; }
set { SetProperty(ref _selectedCOMPort, value); }
}
public LiveGraphViewModel()
{
this.ConnectButtonCommand = new ConnectButtonCommand(this);
ObservableCollection<string> TempCOM = new ObservableCollection<string>();
foreach (string comport in SerialPort.GetPortNames())
TempCOM.Add(comport);
Available_COMPorts = TempCOM;
if(Available_COMPorts.Count > 0)
SelectedCOMPort = Available_COMPorts[0];
}
public void ConnectButton()
{
if (SelectedCOMPort == "COM5")
Connect(SelectedCOMPort);
}
}
LiveGraphView XAML
<UserControl x:Class="SmartAthleticsWPF.Views.LiveGraphView"
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:SmartAthleticsWPF.Views"
xmlns:viewmodels="clr-namespace:SmartAthleticsWPF.ViewModels"
xmlns:commands="clr-namespace:SmartAthleticsWPF.Commands"
xmlns:syncfusion="clr-namespace:Syncfusion.UI.Xaml.Charts;assembly=Syncfusion.SfChart.WPF"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<viewmodels:LiveGraphViewModel x:Key="LIVviewModel"/>
</UserControl.Resources>
<Grid Background="#EDEDED">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.01*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.01*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"/>
<RowDefinition Height="1.2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="0.1*"/>
</Grid.RowDefinitions>
<!--LIVE GRAPH BORDER-->
<Border Grid.Row="1" Grid.RowSpan="2"
Grid.Column="1" Grid.ColumnSpan="2"
Margin="5"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="5"
Padding="10,10,30,10"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<DockPanel>
<Label Content="Live Graph"
DockPanel.Dock="Top"
HorizontalAlignment="Center"
Padding="0,5,0,10" FontSize="22"/>
<syncfusion:SfChart x:Name="LiveGraphChart" >
<syncfusion:SfChart.PrimaryAxis>
<syncfusion:NumericalAxis Header="Seconds"
Maximum="{Binding MaxXAxis}"
Minimum="{Binding MinXAxis}"/>
</syncfusion:SfChart.PrimaryAxis>
<syncfusion:SfChart.SecondaryAxis>
<syncfusion:NumericalAxis Header="Kgf"/>
</syncfusion:SfChart.SecondaryAxis>
<syncfusion:SfChart.Series>
<syncfusion:FastLineBitmapSeries ItemsSource="{Binding FyCircularBuffer}"
XBindingPath="XData" YBindingPath="YData"
StrokeThickness="1" Interior="DarkGreen"
ShowTooltip="False" ShowTrackballInfo="False"
IsSeriesVisible="{Binding FyChecked}"/>
<syncfusion:FastLineBitmapSeries ItemsSource="{Binding MyCircularBuffer}"
XBindingPath="XData" YBindingPath="YData"
StrokeThickness="1" Interior="LimeGreen"
ShowTooltip="False" ShowTrackballInfo="False"
IsSeriesVisible="{Binding MyChecked}"/>
<syncfusion:FastLineBitmapSeries ItemsSource="{Binding FxCircularBuffer}"
XBindingPath="XData" YBindingPath="YData"
StrokeThickness="1" Interior="IndianRed"
ShowTooltip="False" ShowTrackballInfo="False"
IsSeriesVisible="{Binding FxChecked}"/>
<syncfusion:FastLineBitmapSeries ItemsSource="{Binding MxCircularBuffer}"
XBindingPath="XData" YBindingPath="YData"
StrokeThickness="1" Interior="Red"
ShowTooltip="False" ShowTrackballInfo="False"
IsSeriesVisible="{Binding MxChecked}"/>
<syncfusion:FastLineBitmapSeries ItemsSource="{Binding FzCircularBuffer}"
XBindingPath="XData" YBindingPath="YData"
StrokeThickness="1" Interior="BlueViolet"
ShowTooltip="False" ShowTrackballInfo="False"
IsSeriesVisible="{Binding FzChecked}"/>
<syncfusion:FastLineBitmapSeries ItemsSource="{Binding MzCircularBuffer}"
XBindingPath="XData" YBindingPath="YData"
StrokeThickness="1" Interior="Blue"
ShowTooltip="False" ShowTrackballInfo="False"
IsSeriesVisible="{Binding MzChecked}"/>
</syncfusion:SfChart.Series>
</syncfusion:SfChart>
</DockPanel>
</Border>
<!--COP BORDER-->
<Border Grid.Row="2"
Grid.Column="3"
Margin="5"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="5"
Padding="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<DockPanel>
<Label Content="C O P"
Grid.Column="0" Grid.ColumnSpan="2"
DockPanel.Dock="Top"
HorizontalAlignment="Center"
FontSize="16"
FontWeight="Bold"
Padding="0,0,0,5"/>
<syncfusion:SfChart x:Name="CopChart"
VerticalContentAlignment="Stretch"
HorizontalAlignment="Center"
AreaBorderThickness="5"
AreaBorderBrush="#523B97">
<syncfusion:SfChart.PrimaryAxis>
<syncfusion:NumericalAxis Minimum="-20"
Maximum="20"
Interval="10"
PlotOffset="5"
BorderThickness="0"
TickLineSize="0"
FontSize="12">
<syncfusion:NumericalAxis.AxisLineStyle>
<Style TargetType="Line">
<Setter Property="StrokeThickness" Value="0"/>
</Style>
</syncfusion:NumericalAxis.AxisLineStyle>
</syncfusion:NumericalAxis>
</syncfusion:SfChart.PrimaryAxis>
<syncfusion:SfChart.SecondaryAxis>
<syncfusion:NumericalAxis Minimum="-30"
Maximum="30"
Interval="10"
PlotOffset="5"
BorderThickness="0"
TickLineSize="0"
FontSize="12">
<syncfusion:NumericalAxis.AxisLineStyle>
<Style TargetType="Line">
<Setter Property="StrokeThickness" Value="0"/>
</Style>
</syncfusion:NumericalAxis.AxisLineStyle>
</syncfusion:NumericalAxis>
</syncfusion:SfChart.SecondaryAxis>
<syncfusion:SfChart.Annotations>
<syncfusion:LineAnnotation X1="00" X2="00" Y1="-30" Y2="30"
Stroke="DimGray" StrokeThickness="2" StrokeDashArray="4"/>
<syncfusion:LineAnnotation X1="-20" X2="20" Y1="00" Y2="0"
Stroke="DimGray" StrokeThickness="2" StrokeDashArray="4"/>
</syncfusion:SfChart.Annotations>
<syncfusion:SfChart.Series>
<syncfusion:FastScatterBitmapSeries ItemsSource="{Binding COP_DOT}"
XBindingPath="XData" YBindingPath="YData"
Interior="Red" ScatterHeight="20" ScatterWidth="20"/>
</syncfusion:SfChart.Series>
</syncfusion:SfChart>
</DockPanel>
</Border>
<!--SERIAL BORDER-->
<Border Grid.Row="1"
Grid.Column="3"
Margin="5"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="5"
Padding="15,0,15,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="Conexão"
Grid.Column="0" Grid.ColumnSpan="2"
DockPanel.Dock="Top"
HorizontalAlignment="Center"
FontSize="16"
FontWeight="Bold"
Padding="0,0,0,5"/>
<DockPanel Grid.Row="1" Grid.ColumnSpan="2" LastChildFill="True">
<Label Content="Porta COM: "></Label>
<ComboBox ItemsSource="{Binding Available_COMPorts}"
SelectedValue="{Binding SelectedCOMPort, Mode=TwoWay}"
Margin="0,0,0,15" />
<!--SelectedItem="{Binding SelectedCOMPort, Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}"-->
</DockPanel>
<Button Grid.Row="2" Grid.ColumnSpan="2" Content="Connect/Disconnect" HorizontalAlignment="Stretch" Margin="5"
Command="{Binding Path=ConnectButtonCommand, Source={StaticResource LIVviewModel}}"/>
<StackPanel Orientation="Horizontal" Grid.Row="3" Grid.ColumnSpan="2">
<Label Content="Status: "></Label>
<Label Content="{Binding SelectedCOMPort}" Foreground="Red" />
</StackPanel>
</Grid>
</Border>
<Grid Grid.Row="3"
Grid.Column="1" Grid.ColumnSpan="3"
HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!--SERIAL BORDER-->
<Border Grid.Column="0"
Margin="5"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="5"
Padding="20,0,20,0">
</Border>
<!--RECORD BORDER-->
<Border Grid.Column="1"
Margin="5"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="5"
Padding="20,0,20,0">
<Grid Margin="5,10,5,10" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1.5*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Grid.ColumnSpan="2" Margin="0,0,0,10"
Content="Click me" Command="{Binding Path=RecordButtonCommand, Source={StaticResource LIVviewModel}}" />
<Label Content="Record Time (s):"
Grid.Column="0" Grid.Row="1" VerticalAlignment="Center"/>
<TextBlock Text="30" Background="White"
Grid.Column="1" Grid.Row="1"
VerticalAlignment="Center"/>
<Label Content="Name:"
Grid.Column="0" Grid.Row="2" VerticalAlignment="Center"/>
<TextBlock Text="Subject Name"
Grid.Column="1" Grid.Row="2" VerticalAlignment="Center"/>
</Grid>
</Border>
<!--Informações do Gráfico BORDER-->
<Border Grid.Column="2"
Margin="5"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="5"
Padding="10,0,10,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="Informações do Gráfico"
Grid.Column="0" Grid.ColumnSpan="6"
HorizontalAlignment="Center"
FontSize="16" FontWeight="Bold" />
<CheckBox Content="Fy"
Grid.Column="0" Grid.Row="1"
FontWeight="ExtraBlack" FontSize="12"
Foreground="DarkGreen"
HorizontalAlignment="Center"
IsChecked="{Binding FyChecked}" />
<CheckBox Content="My"
Grid.Column="1" Grid.Row="1"
FontWeight="ExtraBlack" FontSize="12"
Foreground="LimeGreen"
HorizontalAlignment="Center"
IsChecked="{Binding MyChecked}" />
<CheckBox Content="Fx"
Grid.Column="2" Grid.Row="1"
FontWeight="ExtraBlack" FontSize="12"
Foreground="IndianRed"
HorizontalAlignment="Center"
IsChecked="{Binding FxChecked}" />
<CheckBox Content="Mx"
Grid.Column="3" Grid.Row="1"
FontWeight="ExtraBlack" FontSize="12"
Foreground="Red"
HorizontalAlignment="Center"
IsChecked="{Binding MxChecked}" />
<CheckBox Content="Fz"
Grid.Column="4" Grid.Row="1"
FontWeight="ExtraBlack" FontSize="12"
Foreground="BlueViolet"
HorizontalAlignment="Center"
IsChecked="{Binding FzChecked}" />
<CheckBox Content="Mz"
Grid.Column="5" Grid.Row="1"
FontWeight="ExtraBlack" FontSize="12"
Foreground="Blue"
HorizontalAlignment="Center"
IsChecked="{Binding MzChecked}" />
<DockPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" LastChildFill="True" HorizontalAlignment="Stretch">
<Label Content="Periodo: " VerticalAlignment="Center"/>
<ComboBox Text="30" Background="White" VerticalAlignment="Center"
SelectedIndex="{Binding PeriodSelectedIndex}"> <!--5-->
<ComboBoxItem Content="100 ms" />
<ComboBoxItem Content="500 ms" />
<ComboBoxItem Content="1 s" />
<ComboBoxItem Content="5 s" />
<ComboBoxItem Content="10 s" />
<ComboBoxItem Content="30 s" />
</ComboBox>
</DockPanel>
<DockPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3" LastChildFill="True" HorizontalAlignment="Stretch">
<Label Content="Amplitude: " VerticalAlignment="Center"/>
<ComboBox Text="30" Background="White" VerticalAlignment="Center"
SelectedIndex="{Binding AmplitudeSelectedIndex}"> <!--3-->
<ComboBoxItem Content="10"/>
<ComboBoxItem Content="100"/>
<ComboBoxItem Content="500"/>
<ComboBoxItem Content="1000"/>
<ComboBoxItem Content="5000"/>
<ComboBoxItem Content="10000"/>
</ComboBox>
</DockPanel>
<Label Grid.Row="2" Grid.Column="3" Grid.ColumnSpan="3" Content="{Binding PesoKg}" ContentStringFormat="Peso (kg): {0}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Label Grid.Row="3" Grid.Column="3" Grid.ColumnSpan="3" Content="{Binding PesoNw}" ContentStringFormat="Força (N): {0}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</Border>
</Grid>
</Grid>
</UserControl>
连接按钮
public class ConnectButtonCommand : ICommand
{
public LiveGraphViewModel ViewModel { get; set; }
public ConnectButtonCommand(LiveGraphViewModel viewModel)
{
this.ViewModel = viewModel;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
this.ViewModel.ConnectButton();
}
}
数据上下文
public partial class LiveGraphView : UserControl
{
private LiveGraphViewModel _vm;
public LiveGraphView()
{
InitializeComponent();
this._vm = new LiveGraphViewModel();
this.DataContext = this._vm;
}
}
解决方案
正如@Clemens 所提到的,我同时有两个视图模型实例。一个在 UserControl 的构造函数(后面的代码)中创建,另一个在 XAML 资源中创建。
所以,我删除了最后一个,一切正常。
<!--
<UserControl.Resources>
<viewmodels:LiveGraphViewModel x:Key="LIVviewModel"/>
</UserControl.Resources>
-->
<Label Content="Porta COM: "></Label>
<ComboBox ItemsSource="{Binding Available_COMPorts}"
SelectedValue="{Binding SelectedCOMPort, Mode=TwoWay}" />
<Button Content="Connect/Disconnect"
Command="{Binding Path=ConnectButtonCommand}" />
推荐阅读
- java - 使用 BufferedReader 读取 JSON 文件两次
- charts - 谷歌图表时间线标签未显示在框中
- sql-server - 最大限度。在 SQL Server 中并行运行的查询
- docker - xpra 和 sudo / sudo 和“成为用户”有什么区别
- php - 如何用 2 个字符串在 php 中拆分数组?
- amazon-ec2 - Chef Kitchen CI 验证不收敛。现有服务器测试
- java - 如何在 Apache vfs 中获取文件的日期
- npm - 如何从终端退出本地主机
- javascript - NEAT 算法,提供的库中缺少函数定义
- r - 对具有特殊列(带列表的列)的数据框执行正弦函数和算术运算