WPF MVVM:ComboBox SelectedValue 绑定

WPF MVVM: ComboBox SelectedValue binding

由于评论中的反馈,我更新了我的问题。

我正在尝试根据另一个 ComboBox (cbLicenseHolder) 中的 SelectedValue/Item 对 ComboBox (cbVehicle) 进行排序和填充。 属性的绑定是通过 BindableCollection 完成的(与 ObservableCollection 基本相同)。

下面你会看到我的ViewModel

namespace Ridel.Hub.ViewModels {

    public class TripViewModel : Conductor<IScreen>.StackNavigation {

        private readonly IWindowManager windowManager;

        private BindableCollection<LicenseHolder> _licenseHolders;
        public BindableCollection<LicenseHolder> LicenseHolders {

            get => _licenseHolders;
            set => SetAndNotify(ref this._licenseHolders, value);
        }

        private BindableCollection<License> _licenses;
        public BindableCollection<License> Licenses {

            get => _licenses;
            set => SetAndNotify(ref this._licenses, value);
        }

        #region Constructor
        public TripViewModel(IWindowManager windowManager) {

            this.windowManager = windowManager;
            LicenseHolders = new BindableCollection<LicenseHolder>();
            Licenses = new BindableCollection<License>();
        }
        #endregion // Constructor

        #region ComboBoxes

        public void FillComboBoxLicenseHolders() {

            try {

                DataSet ds = new DataSet();

                using (SqlConnection sqlCon = new SqlConnection(ConnectionString.connectionString)) {

                    SqlDataAdapter sqlDA = new();
                    sqlDA.SelectCommand = new SqlCommand("select Foretaksnavn from tblLicenseHolder", sqlCon);
                    sqlDA.Fill(ds);
                }

                DataTable dt = new();
                dt = ds.Tables[0];

                for (int i = 0; i < dt.Rows.Count; i++) {

                    DataRow dr = dt.NewRow();
                    dr = dt.Rows[i];
                    LicenseHolder licenseHolder = new();
                    licenseHolder.Foretaksnavn = dr["Foretaksnavn"].ToString();

                    LicenseHolders.Add(licenseHolder);
                }

            } catch (Exception ex) {

                MessageBox.Show(ex.Message, "Message", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        public void FillComboBoxLicenses() {

            Licenses.Clear();

            try {

                DataSet ds = new();

                using (SqlConnection sqlCon = new SqlConnection(ConnectionString.connectionString)) {

                    SqlDataAdapter sqlDA = new();
                    sqlDA.SelectCommand = new SqlCommand("fillLicensesComboBox", sqlCon);
                    sqlDA.SelectCommand.CommandType = CommandType.StoredProcedure;
                    sqlDA.SelectCommand.Parameters.Add("@Foretaksnavn", SqlDbType.NVarChar).Value = CbLicenseHolderSelection.ToString();
                    sqlDA.Fill(ds);
                }

                DataTable dt = new();
                dt = ds.Tables[0];

                for (int i = 0; i < dt.Rows.Count; i++) {

                    DataRow dr = dt.NewRow();
                    dr = dt.Rows[i];
                    License license = new();
                    license.KjøretøyID = dr["KjøretøyID"].ToString();

                    Licenses.Add(license);
                }

            } catch (Exception ex) {

                MessageBox.Show(ex.Message, "Message", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        private string _cbLicenseHolderSelection;
        public string CbLicenseHolderSelection {

            get { return this._cbLicenseHolderSelection; }
            set { SetAndNotify(ref this._cbLicenseHolderSelection, value);

                if (value != null) {

                    FillComboBoxLicenses();
                }
            }
        }

如您所见,我有两个 BindableCollection,一个名为 LicenseHolders,另一个名为 LicensesLicenseHolders 绑定到 cbLicenseHolderLicenses 绑定到 cbVehicle

还有,你看我加了我的方法; FillComboBoxLicenses,到CbLicenseHolderSelection 属性,在下面的XAML,你会看到我已经尝试将属性绑定到SelectedValue ] 的 cbLicenseHolder.

但我显然在这里遗漏了一张图片。 cbVehicle 未被填充。

XAML 下面:

<ComboBox Name="cbLicenseHolder" Canvas.Left="50" Canvas.Top="204" Width="291"               
          ItemsSource="{Binding LicenseHolders, Mode=TwoWay}"                 
          Loaded="{s:Action FillComboBoxLicenseHolders}"    
          DisplayMemberPath="Foretaksnavn"
          SelectedValue="{Binding CbLicenseHolderSelection, UpdateSourceTrigger=PropertyChanged}"
          FontSize="12"
/>
        
<ComboBox Name="cbVehicle" Canvas.Left="381" Canvas.Top="204" Width="269"
          ItemsSource="{Binding Licenses, Mode=TwoWay}"
          DisplayMemberPath="KjøretøyID"
          FontSize="12" 
          IsEnabled="True"
          IsSynchronizedWithCurrentItem="True"
/>

LicenseHolder.csLicense.cs 都实现了 PropertyChangedBase。 它们的属性如下所示:

private string _foretaksnavn;
public string Foretaksnavn {
    get { return this._foretaksnavn; }
    set { SetAndNotify(ref this._foretaksnavn, value); }
}

SetAndNotify 是一个框架函数 - 它是这样做的:

"Takes, by reference, a field, and its new value. If field != value, will set field = value and raise a PropertyChanged notification."

我的stored procedure:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[getLicense]
    @Foretaksnavn nvarchar(50)
AS 
SELECT tblLicense.ID, LøyvehaverID, KjøretøyID
FROM tblLicense
INNER JOIN tblLicenseHolder
ON tblLicense.LøyvehaverID = tblLicenseHolder.Foretaksnavn
WHERE tblLicense.LøyvehaverID = @Foretaksnavn

不要将此作为答案,而是作为澄清问题以便更好地理解问题。
我只是需要一些解释,包括代码,所以我必须以答案的形式给他们。

  1. 如下更改属性、方法和绑定的实现并报告结果:
private LicenseHolder _cbLicenseHolderSelection;
public LicenseHolder CbLicenseHolderSelection {

   get { return this._cbLicenseHolderSelection; }
   set { SetAndNotify(ref this._cbLicenseHolderSelection, value);

       if (value != null) {

           FillComboBoxLicenses();
       }
   }
}
<ComboBox Name="cbLicenseHolder" Canvas.Left="50" Canvas.Top="204" Width="291"               
          ItemsSource="{Binding LicenseHolders, Mode=TwoWay}"                 
          Loaded="{s:Action FillComboBoxLicenseHolders}"    
          DisplayMemberPath="Foretaksnavn"
          SelectedItem="{Binding CbLicenseHolderSelection, UpdateSourceTrigger=PropertyChanged}"
          FontSize="12"
/>
public ObservableCollection<License> Licenses {get;}
    = new ObservableCollection<License>();
public void FillComboBoxLicenses() {

    try {

        DataSet ds = new();

        using (SqlConnection sqlCon = new SqlConnection(ConnectionString.connectionString)) {

            SqlDataAdapter sqlDA = new();
            sqlDA.SelectCommand = new SqlCommand("fillLicensesComboBox", sqlCon);
            sqlDA.SelectCommand.CommandType = CommandType.StoredProcedure;
            sqlDA.SelectCommand
                     .Parameters
                     .Add("@Foretaksnavn", SqlDbType.NVarChar)
            // It is necessary to specify a specific property for the Value.
                     .Value = CbLicenseHolderSelection.SomeProperty.ToString();
            sqlDA.Fill(ds);
        }

        DataTable dt = new();
        dt = ds.Tables[0];

        Licenses.Clear();

        for (int i = 0; i < dt.Rows.Count; i++) {

            DataRow dr = dt.NewRow();
            dr = dt.Rows[i];
            License license = new();
            license.KjøretøyID = dr["KjøretøyID"].ToString();

            Licenses.Add(license);
        }

    } // On this line (after the for loop), set a breakpoint.

    catch (Exception ex) {

        MessageBox.Show(ex.Message, "Message", MessageBoxButton.OK, MessageBoxImage.Information);
    }
}

在循环后的行中的 FillComboBoxLicenses 方法中停止后,还要告诉 Licenses 集合中有多少项。