【问题标题】:Dynamically update combobox itemsource in listview per row每行动态更新列表视图中的组合框项目源
【发布时间】:2013-10-11 00:39:12
【问题描述】:

我目前有一个带有 3 个组合框的 Listview 框。我从 sql 数据库中填充它们。对于每一行,我想让第三个组合框根据第二个组合框的选定值更改其内容。

组合框将是:cmbx1(员工[jack, jill, tom, lisa]),cmbx2(产品[钢笔,铅笔,订书机]),cmbx3(颜色 - 将根据产品可用的颜色而动态变化)

产品和颜色选项:笔[红、蓝、黑];铅笔[黑、橙、红];订书机[粉色、蓝绿色、紫色、棕色]

如果对于第 1 行,用户选择了一支笔,那么只有该产品的可用颜色将列在该行的颜色组合框中。根据所选产品,下一行可能有不同的颜色选项。

这是可能的还是我应该找到另一种方法来实现结果?

这是目前拥有的...

<ListView.View>
    <GridView>
        <GridViewColumn Header="Employee" Width="150">
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox ItemsSource="{Binding lStrEmployee}" Width="120" />
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>
        <GridViewColumn Header="Product" Width="150">
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox ItemsSource="{Binding lStrProduct}" Width="120" />
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>
        <GridViewColumn Header="Color" Width="150">
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox ItemsSource="{Binding lStrColor}" Width="120" />
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>
</ListView.View>

后面的代码

List<Int32> liEmployee = new List<Int32>();
List<string> lsEmployee = new List<string>();
List<Int32> liProduct = new List<Int32>();
List<string> lsProduct = new List<string>();
List<Int32> liColor = new List<Int32>();
List<string> lsColor = new List<string>();

SqlConnection conn = new SqlConnection("Data Source=localhost\\SQLEXPRESS;Initial Catalog=testDB;Persist Security Info=True;User ID=USER;Password=PASSWORD;");//Connect Timeout=900
SqlCommand cmd1 = new SqlCommand("select id,employee from testDB.dbo.dmEmployee where inactive=0", conn);
SqlCommand cmd2 = new SqlCommand("select id,Product from testDB.dbo.tblProductList where inactive=0", conn);
SqlCommand cmd3 = new SqlCommand("select id,Color from testDB.dbo.Color where inactive=0", conn);

conn.Open();
SqlDataReader dr1 = cmd1.ExecuteReader();
while (dr1.Read())
{
    liEmployee.Add(dr1.GetInt32(dr1.GetOrdinal("id")));
    lsEmployee.Add(dr1.GetString(dr1.GetOrdinal("employee")));
}
conn.Close();
conn.Open();
SqlDataReader dr2 = cmd2.ExecuteReader();
while (dr2.Read())
{
    liProduct.Add(dr2.GetInt32(dr2.GetOrdinal("id")));
    lsProduct.Add(dr2.GetString(dr2.GetOrdinal("Product")));
}
conn.Close();
conn.Open();
SqlDataReader dr3 = cmd3.ExecuteReader();
while (dr3.Read())
{
    liColor.Add(dr3.GetInt32(dr3.GetOrdinal("id")));
    lsColor.Add(dr3.GetString(dr3.GetOrdinal("Color")));
}
conn.Close();


List<lvItem> itemFound = new List<lvItem>();
itemFound.Clear();
lvItem puzzlePieces;
for (int cnt = 0; cnt < 10; cnt++)
{
    puzzlePieces = new lvItem();

    puzzlePieces.lStrEmployee = lsEmployee;
    puzzlePieces.lStrDatabase = lsDatabase;
    puzzlePieces.lStrProvider = lsProvider;

    itemFound.Add(puzzlePieces);
}
list1.ItemsSource = itemFound;

谢谢!

【问题讨论】:

    标签: wpf listview dynamic-binding


    【解决方案1】:

    我很惊讶您的问题没有得到任何答案。也许是因为您似乎没有以 WPF 方式做事,或者可能是因为您要求太多?

    首先...您需要创建一个实现INotifyPropertyChanged 接口并包含在ListView 的每一行中显示所需的所有属性的数据类型类。在您的情况下,您需要三个集合和三个选定的项目值。例如,您可以这样做(自己实现INotifyPropertyChanged 接口):

    public class RowData : INotifyPropertyChanged
    {
        public ObservableCollection<Employee> Employees { get; set; }
        public Employee SelectedEmployee { get; set; }
        public ObservableCollection<Product> Products { get; set; }
        public Product SelectedProduct { get; set; }
        public ObservableCollection<Brush> Colours { get; set; }
        public Brush SelectedColour { get; set; }
    }
    

    注意使用Brush 类而不是Color 结构,这是因为Brush 是一个类,这意味着我们可以绑定到它,也因为它更主要地用于WPF。

    但是,除了Colours 集合之外,每一行中的每个对象都使用相同的集合并不是最优的,因为每一行的集合可能不同。话虽如此,这正是我要做的,因为我解释起来会更快,您可以在稍后阶段自己改进您的代码:

    现在您有了数据类型类,我们需要添加该类型的属性以绑定到您的ListView 控件。如果您使用MainWindow 后面的代码,那么让我们为其创建一个DependencyProperty

    public static readonly DependencyProperty RowDataProperty = DependencyProperty.
        Register("RowData", typeof(ObservableCollection<RowData>), typeof(MainWindow), 
        new UIPropertyMetadata(new ObservableCollection<RowData>()));
    
    public ObservableCollection<RowData> RowData
    {
        get { return (ObservableCollection<RowData>)GetValue(RowDataProperty); }
        set { SetValue(RowDataProperty, value); }
    }
    

    填充集合后,您现在可以将其绑定到ListView 控件:

    xmlns:Local="clr-namespace:YourWpfApplicationName"
    ...
    <ListView ItemsSource="{Binding RowData, RelativeSource={RelativeSource AncestorType={
        x:Type Local:MainWindow}}}">
        ...
    </ListView>
    

    简而言之,RelativeSource Binding 只是在寻找您在后面的代码中定义的属性。现在,如何定义ComboBox 应该出现在每个GridViewColumn 中?你需要定义GridViewColumn.CellTemplate:

    <GridViewColumn Header="Employees">
        <GridViewColumn.CellTemplate>
            <DataTemplate>
                <ComboBox ItemsSource="{Binding Employees}" SelectedItem="{Binding 
                    SelectedEmployee}" />
            </DataTemplate>
        </GridViewColumn.CellTemplate>
    </GridViewColumn>
    

    您需要定义此示例中的其他列。所以这个难题的最后一部分是如何根据其他ComboBoxes 的选定值更新Colours ComboBox 的内容?答案在于您在 RowData 类中选择的值属性:

    public Employee SelectedEmployee
    {
        get { return selectedEmployee; }
        set
        {
            selectedEmployee = value;
            NotifyPropertyChanged(SelectedEmployee);
            Colours = GetColours();
        }
    }
    
    private ObservableCollection<Brush> GetColours()
    {
        ObservableCollection<Brush> newColours = new ObservableCollection<Brush>();
        if (SelectedEmployee.Name == "Some Name" && SelectedProduct.Name == 
            "Some Product") newColours.AddRange( new List<Brush>() { Brushes.Red, 
            Brushes.White, Brushes.Blue } );
        else ...
    }
    

    有很多方法可以做到这一点,我将把它留给你。您现在应该有一个可行的示例,我现在意识到为什么没有人回答您的问题......对于任何理智的人来说都太多了!在花了这么长时间之后,如果您尝试自己解决您发现的任何小问题并希望它对您有所帮助,我将不胜感激。

    【讨论】:

    • 抱歉,我花了这么长时间才回复这个问题。这是我的第一个 WPF 项目,我没有接受过“WPF 方式”的培训,所以这对我来说是一次重要的学习经历。感谢您提供详细的示例。
    猜你喜欢
    • 1970-01-01
    • 2015-06-05
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 2021-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多