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
,另一个名为 Licenses
。 LicenseHolders
绑定到 cbLicenseHolder
,Licenses
绑定到 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.cs
和 License.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
不要将此作为答案,而是作为澄清问题以便更好地理解问题。
我只是需要一些解释,包括代码,所以我必须以答案的形式给他们。
- 如下更改属性、方法和绑定的实现并报告结果:
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 集合中有多少项。
由于评论中的反馈,我更新了我的问题。
我正在尝试根据另一个 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
,另一个名为 Licenses
。 LicenseHolders
绑定到 cbLicenseHolder
,Licenses
绑定到 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.cs
和 License.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
不要将此作为答案,而是作为澄清问题以便更好地理解问题。
我只是需要一些解释,包括代码,所以我必须以答案的形式给他们。
- 如下更改属性、方法和绑定的实现并报告结果:
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 集合中有多少项。