首页 > 解决方案 > 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>

这实际上是否可行,或者是否应该将替代方法应用于这种情况?从逻辑上讲,这并不是一个复杂的过程,但是我一直无法实施解决方案。

标签: c#wpfxamlcombobox

解决方案


以经典形式,我几乎放弃后不久就解决了这个问题!

解决方案是将对象集合绑定到主窗口类中的数据网格,然后绑定国家、国家、城市和城市的各个属性。这还包括为相关下拉列表添加更新触发器,以便可以调用类中的更新方法。

<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;
    }
}

推荐阅读