首页 > 解决方案 > WPF MVVM 组合框 SelectedItem 无法正常工作

问题描述

我已经搜索并阅读了几篇文章,但我找不到我做错了什么。

我有一个带有ObservableCollection<string> Available_COMPortsas的 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”)。SelectedCOMPortINotifyPropertyChangedAvailable_COMPortsSelectedCOMPort = "Available_COMPorts[0]"

当我运行代码时,ComboBox 有三个项目,选中的项目是“COM6”,标签显示“COM6”(一切正常)。然后我选择“COM5”,标签将其值更新为“COM5”。这在以下图片中进行了介绍。

带有 SelectedCOMPort 的图像 =

带有 SelectedCOMPort 的图像 =

问题是当我尝试访问SelectedCOMPortViewModel,因为我需要选择的项目来连接我的 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;
    }
}

在此处输入图像描述

标签: wpfmvvmcomboboxbinding

解决方案


正如@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}" />


推荐阅读