c# - WPF DataGrid - 从 DataGrid ItemsSource 对象的集合值中设置唯一的每行(对象)组合框值
问题描述
我正在尝试根据行(对象)的单个集合值设置列组合框值,以便每一行具有基于另一个值的不同选项列表。
例如。
第 1 列:国家/地区组合框 - 例如从 {“UK”、“USA”、“France”} 中选择的 UK
第 2 列:城市组合框 - 例如选择 LA { "New York", "LA", "Texas" }(基于美国之前的选择)
下面是我的示例数据对象
public class ExampleData
{
public List<string> countries { get; set; }
public List<string> cities { get; set; }
public string country { get; set; }
public string city { get; set; }
public ExampleData(string country)
{
this.country = country;
countries = new List<string>() { "UK", "USA", "France" };
}
// Example update method to change dependant options
public void UpdateOptions()
{
if (country == "UK")
{
cities = new List<string>() { "London", "Bristol", "Birmingham" };
}
else if (country == "USA")
{
cities = new List<string>() { "New York", "LA", "Texas" };
}
else if (country == "France")
{
cities = new List<string>() { "Paris", "Lyon", "Nice" };
}
else
{
cities = new List<string>();
}
}
}
然后,我将创建数据的示例集合,以在数据网格中显示
public void TestScenario()
{
ExampleDataCollection = new List<ExampleData>();
exampleDataList.Add(new ExampleData("UK"));
exampleDataList.Add(new ExampleData("USA"));
exampleDataList.Add(new ExampleData("France"));
DataGrid.ItemsSource = ExampleDataCollection ;
}
然后在 xaml 中,我将对象集合作为 ItemsSource 绑定到数据网格,而每个列组合框将绑定到对象自己的集合,该集合将是每行(对象)独立的。这类似于 ExampleData.countries,其中 ExampleData.Country 是选定的值。
<DataGrid
Name="ExampleDataGrid"
AutoGenerateColumns="False"
ItemsSource="{Binding ExampleDataCollection}"
>
<DataGrid.Columns>
<DataGridComboBoxColumn
Header="country"
ItemsSource="{Binding ExampleData.countries}"
SelectedValueBinding="{Binding ExampleData.country}"
/>
<DataGridComboBoxColumn
Header="city"
ItemsSource="{Binding ExampleData.cities}"
SelectedValueBinding="{Binding ExampleData.city}"
/>
</DataGrid.Columns>
</DataGrid>
这实际上是否可行,或者是否应该将替代方法应用于这种情况?从逻辑上讲,这并不是一个复杂的过程,但是我一直无法实施解决方案。
解决方案
以经典形式,我几乎放弃后不久就解决了这个问题!
解决方案是将对象集合绑定到主窗口类中的数据网格,然后绑定国家、国家、城市和城市的各个属性。这还包括为相关下拉列表添加更新触发器,以便可以调用类中的更新方法。
<DataGrid
Name="ExampleDataGrid"
AutoGenerateColumns="False"
>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Country">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding countries}" SelectedItem="{Binding Country, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="city">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding cities}" SelectedItem="{Binding City, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
国家和城市的字符串列表已更新为可观察的集合,以便新的组合框在更改时更新它们。添加 INotifyPropertyChanged 意味着当国家或城市从与其绑定的下拉选择中更改时,它会调用 OnPropertyChanged 方法。
这让我可以调用另一种方法来更新新的城市列表。必须注意的是,您不能简单地通过 equals 将现有集合替换为新集合。它必须具有与之关联的更改,例如添加或删除(不清楚)才能实际更新。见下文。
public class ExampleData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<string> countries { get; set; }
public ObservableCollection<string> cities { get; set; }
public ObservableCollection<string> towns { get; set; }
private string country;
private string city;
private string town;
public string Country
{
get
{
return country;
}
set
{
country = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("Country");
}
}
public string City
{
get
{
return city;
}
set
{
city = value;
}
}
public string Town { get; set; }
public ExampleData(string country)
{
this.country = country;
countries = new ObservableCollection<string>() { "UK", "USA", "France" };
cities = new ObservableCollection<string>() { "London", "Bristol", "Plymouth" };
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
UpdateOptions();
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public void UpdateOptions()
{
List<string> oldCities = cities.ToList<string>();
List<string> newCities;
foreach (string city in oldCities)
{
cities.Remove(city);
}
if (country == "UK")
{
newCities = new List<string>() { "London", "Bristol", "Birmingham" };
}
else if (country == "USA")
{
newCities = new List<string>() { "New York", "LA", "Texas" };
}
else if (country == "France")
{
newCities = new List<string>() { "Paris", "Lyon", "Nice" };
}
else
{
newCities = new List<string>();
}
foreach (string city in newCities)
{
cities.Add(city);
}
}
}
没有对主窗口代码进行任何更改,它与下面保持相同。
public partial class MainWindow : Window
{
public List<ExampleData> exampleDataList;
public MainWindow()
{
InitializeComponent();
TestScenario();
}
public void TestScenario()
{
exampleDataList = new List<ExampleData>();
exampleDataList.Add(new ExampleData("UK"));
exampleDataList.Add(new ExampleData("USA"));
exampleDataList.Add(new ExampleData("France"));
ExampleDataGrid.ItemsSource = exampleDataList;
}
}
推荐阅读
- reactjs - 特殊属性更改时仅运行一次 useEffect
- php - 具有多个值列的 3 个表的 sql 查询
- javascript - 如何将 Google Analytics 集成到您的 Nuxt.js 应用程序中
- sql - 查找最新记录
- c# - 清除 Console.ReadLine 和 Console.Read 之间的控制台缓冲区
- c - 用于判断数字是否为“完美数字”的代码
- kotlin - Jetpack Compose Row 水平排列约束
- bash - 如何使用 bash 脚本/CMakeLists.txt 运行 cmake
- database - 如何在 sequelize 中使用 exclude 定义 postgresql int8range
- javascript - 无法在药丸选项卡上触发点击事件