【问题标题】:DataGridComboBoxColumn different ItemsSource for different rowsDataGridComboBoxColumn 不同行的不同 ItemsSource
【发布时间】:2017-01-16 15:53:54
【问题描述】:

Here 提出了与我的问题类似的问题,但我没有在那里找到解决方案。

我的问题:如何将不同的数据(比如列表)绑定到不同行中每个 ComboBox 的“DataGridComboBoxColumn”。这是我尝试过的代码

XAML:

<Grid>
    <DataGrid x:Name="dg_TimeTable" AutoGenerateColumns="False" Margin="0,0,0,97" ColumnWidth="*">
        <DataGrid.Columns>
            <DataGridTextColumn IsReadOnly="True" Binding="{Binding CLASS}" Header="CLASS" />

            <DataGridComboBoxColumn Header="PERIOD" x:Name="gPeriods" SelectedValueBinding="{Binding PERIOD, Mode=TwoWay}" DisplayMemberPath="{Binding PERIOD}" />

            <DataGridComboBoxColumn Header="TEACHERS" x:Name="gTeachers" SelectedValueBinding="{Binding TEACHER, Mode=TwoWay}" DisplayMemberPath="{Binding TEACHER}" />

            <DataGridComboBoxColumn Header="SUBJECTS" x:Name="gSubjects" SelectedValueBinding="{Binding SUBJECT, Mode=TwoWay}" DisplayMemberPath="{Binding SUBJECT}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

.cs

using System.Collections.ObjectModel; // For ObservableCollection

public partial class MainWindow : Window
{
    ObservableCollection<string> listTeachersSix = null;
    ObservableCollection<string> listTeachersSeven = null;
    ObservableCollection<string> listTeachersEight = null;
    ObservableCollection<string> listTeachersNine = null;
    ObservableCollection<string> listTeachersTen = null;
    ObservableCollection<string> listSubjects = null;
    ObservableCollection<int> listPeriods = null;

    public MainWindow()
    {
        InitializeComponent();

        listTeachersSix = new ObservableCollection<string>();
        listTeachersSeven = new ObservableCollection<string>();
        listTeachersEight = new ObservableCollection<string>();
        listTeachersNine = new ObservableCollection<string>();
        listTeachersTen = new ObservableCollection<string>();
        listSubjects = new ObservableCollection<string>();
        listPeriods = new ObservableCollection<int>();

        listTeachersSix.Add("Vijay");
        listTeachersSix.Add("Naveen");
        listTeachersSix.Add("Gopal");
        listTeachersSix.Add("Somesh");

        listTeachersSeven.Add("Raj");
        listTeachersSeven.Add("Rama Krishna");
        listTeachersSeven.Add("Rakesh");
        listTeachersSeven.Add("Ram Babu");

        listTeachersEight.Add("Murali");
        listTeachersEight.Add("Ritesh");
        listTeachersEight.Add("Nagesh");
        listTeachersEight.Add("Tarun");

        listTeachersNine.Add("Bhaskar");
        listTeachersNine.Add("Babji");
        listTeachersNine.Add("Bhanu");
        listTeachersNine.Add("Balaji");

        listTeachersTen.Add("Lal");
        listTeachersTen.Add("Mohan");
        listTeachersTen.Add("Raj Sekhar");
        listTeachersTen.Add("Sunil");

        for (int i = 0; i <= 8; i++)
            listPeriods.Add(i);

        listSubjects.Add("Maths");
        listSubjects.Add("Physics");
        listSubjects.Add("Social");
        listSubjects.Add("English");
        listSubjects.Add("Hindi");
        listSubjects.Add("Telugu");


        List<Info> listTimeTable = new List<Info>()
        {
            new Info () { CLASS="6", PERIOD=1, TEACHER="Vijay", SUBJECT="Maths" },
            new Info () { CLASS="7", PERIOD=5, TEACHER="Raj", SUBJECT="Physics" },
            new Info () { CLASS="8", PERIOD=7, TEACHER="Murali", SUBJECT="Social" },
            new Info () { CLASS="10", PERIOD=4, TEACHER="Mohan", SUBJECT="English" },
            new Info () { CLASS="6", PERIOD=8, TEACHER="Naveen", SUBJECT="Maths" },
            new Info () { CLASS="9", PERIOD=3, TEACHER="Bhaskar", SUBJECT="Hindi" },
            new Info () { CLASS="8", PERIOD=6, TEACHER="Ritesh", SUBJECT="English" },
            new Info () { CLASS="10", PERIOD=2, TEACHER="Lal", SUBJECT="Social" }
        };

        dg_TimeTable.ItemsSource = listTimeTable;

        gPeriods.ItemsSource = listPeriods;

        gSubjects.ItemsSource = listSubjects;

        gTeachers.ItemsSource = listTeachersSix;

    }
}

public class Info
{
    public string CLASS { get; set; }
    public int PERIOD { get; set; }
    public string SUBJECT { get; set; }
    public string TEACHER { get; set; }
}

当我运行这段代码时,输​​出如下。

正如你们在我的代码中看到的,不同的班级有不同的老师。当我点击说第 9 课时,

"listTeachersNine" 应添加到 "gTeachers.ItemsSource"。但是如果我这样做了

gTeachers.ItemsSource = listTeachersNine;

所有其他行都在起作用。如何在不更改其他行的情况下做到这一点。请给我一些想法......提前谢谢

更新:

即使我在下面的代码中尝试了这个

 private void dg_TimeTable_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        int num = (sender as DataGrid).SelectedIndex;
        try
        {


            if (num == 0)
            {
                //listTeachersSix.Clear();

                //listTeachersSix.Add("Vijay");
                //listTeachersSix.Add("Naveen");
                //listTeachersSix.Add("Gopal");
                //listTeachersSix.Add("Somesh");
                gTeachers.ItemsSource = listTeachersSix;

            }
            else if (num == 1)
            {
                //listTeachersSix.Clear();

                //listTeachersSix.Add("Raj");
                //listTeachersSix.Add("Rama Krishna");
                //listTeachersSix.Add("Rakesh");
                //listTeachersSix.Add("Ram Babu");
                gTeachers.ItemsSource = listTeachersSeven;
            }
            else if (num == 2)
            {
                //listTeachersSix.Clear();

                //listTeachersSix.Add("Murali");
                //listTeachersSix.Add("Ritesh");
                //listTeachersSix.Add("Nagesh");
                //listTeachersSix.Add("Tarun");
                gTeachers.ItemsSource = listTeachersEight;

            }
       }

我尝试了注释部分和未注释部分,但没有用。当我启动我的应用程序时,它显示如上图的第一张图。但是当点击特定行时,所有其他行数据都消失了。但问题是,它正在更新新的教师数据。看下面两张图。

所以在不改变其他行的情况下,我可以更新我想要的行.....

【问题讨论】:

  • 你解决了吗?我遇到了问题。

标签: c# wpf wpfdatagrid datagridcomboboxcolumn


【解决方案1】:

我有几种方法可以做到这一点。

如果您不关心严格的 MVVM 设计,您可以使用 IValueConverter,将其传递给您的 CLASS,然后让转换器确定要返回哪个列表。类似于

public object Convert(object value, Type targetType,
    object parameter, CultureInfo culture)
{
    string key = value as string;
    switch (key)
    {
        case "1":
            return SomethingStatic.TeacherList1;
        case "2":
            return SomethingStatic.TeacherList2;
        ...
    }
}

如果您想让它动态化并避免在转换器中硬编码列表引用,您可以使用 IMultiValueConverter 并将变量数组作为另一个绑定值传递给它,并调整代码以简单地从传递的数组中找到正确的 ItemsSource来自其他绑定值。

请注意,要使用其中任何一个,您可能必须从 DataGridComboBoxColumn 切换到 DataGridTemplateColumn,因为从 ComboBoxColumn 绑定将无法正常工作。

<DataGridTemplateColumn Header="TEACHERS">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding CLASS, Converter={StaticResource TestConverter}}" 
                      SelectedItem="{Binding TEACHER}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

另一个替代解决方案是将ValidTeachers 列表添加到每个DataRow 的项目中,在您的情况下为Info 对象。

public class Info
{
    public string CLASS { get; set; }
    public int PERIOD { get; set; }
    public string SUBJECT { get; set; }
    public string TEACHER { get; set; }
    public List<string> ValidTeachers { get; set; }
}

您还需要一个更改事件,因此每当 CLASS 更改时,ValidTeachers 数组就会更新。

我确信还有其他可能更简洁的选项,但如果您正在寻找简单易行的东西,我会推荐其中之一。

【讨论】:

  • 第二种解决方案非常好而且简单。我会试一试,很快就会在这里更新。谢谢:)
  • @Gopi gTeachers 是一个DataGridComboBoxColumn,因此在此处设置ItemsSource 适用于所有行。您只想为所选行设置ItemsSource。正如我在答案中发布的那样,我建议使用转换器。您也许可以在后面编写一些代码以在所选行中找到 ComboBox 来改变它,但在我看来这会更困难。
  • 你能看到这个问题吗plz stackoverflow.com/questions/40416448/…
【解决方案2】:

参考链接msdn link

我现在不能花太多时间在这上面。我拿走了您的原始代码并添加到其中。它不完整,但会节省一些精力。

XAML

    <Grid>
    <DataGrid x:Name="dg_TimeTable" AutoGenerateColumns="False" Margin="0,0,0,97" ColumnWidth="*" PreparingCellForEdit="dg_TimeTable_PreparingCellForEdit">
        <DataGrid.Columns>
            <DataGridTextColumn IsReadOnly="True" Binding="{Binding CLASS}" Header="CLASS" />

            <DataGridComboBoxColumn Header="PERIOD" x:Name="gPeriods" SelectedValueBinding="{Binding PERIOD, Mode=TwoWay}" DisplayMemberPath="{Binding PERIOD}" />

            <DataGridComboBoxColumn Header="TEACHERS" x:Name="gTeachers" SelectedValueBinding="{Binding TEACHER, Mode=TwoWay}" DisplayMemberPath="{Binding TEACHER}" />

            <DataGridTemplateColumn Header="TEACHERS" x:Name="colTeacherList" >
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=TEACHER, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <ComboBox Name="cmbTeacherList" SelectedItem="{Binding myItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>

            <DataGridComboBoxColumn Header="SUBJECTS" x:Name="gSubjects" SelectedValueBinding="{Binding SUBJECT, Mode=TwoWay}" DisplayMemberPath="{Binding SUBJECT}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

C#代码

        private void dg_TimeTable_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
    {
        int rowIndex = dg_TimeTable.SelectedIndex;

        if (e.Column == colTeacherList)
        {
            FrameworkElement element = e.EditingElement;
            ComboBox cb = GetVisualChild<ComboBox>(element);
            if (cb != null)
            {
                switch(dg_TimeTable.SelectedIndex)
                {
                    case 1:
                        cb.ItemsSource = listTeachersSeven;
                        break;
                    case 2:
                        cb.ItemsSource = listTeachersEight;
                        break;
                    default:
                        cb.ItemsSource = listTeachersSix;
                        break;
                }                        
            }
        }
    }

    static T GetVisualChild<T>(Visual parent) where T : Visual
    {
        T child = default(T);
        int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < numVisuals; i++)
        {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
            if (child == null)
            {
                child = GetVisualChild<T>(v);
            }
            if (child != null)
            {
                break;
            }
        }
        return child;
    }

【讨论】:

  • @Makul Varshney 您的代码示例非常适合将特定列表绑定到特定组合框。但我得到“双向绑定需要路径或 XPath”异常。现在我正在处理那个异常。完成工作后更新您。谢谢:)
【解决方案3】:

查看hereVincent Sibal - MSFT的答案:

这应该可以帮助您根据在同一行的另一列中的选择设置某一行中一列的 ItemsSource。每次单击 ComboBox 编辑值时,它都会使用样式设置 ItemsSource。

这是上面网站给出的示例,以防将来删除链接:

例如,如果我有一个 DataGrid,并且我希望标记为 Current Category 的列中的选择会影响 DataGridComboBoxColumn 中称为 Current Product 的选项。

ProductsInCategory 集合/列表中的项目用作当前产品列的可选值。此列表中的项目在 CurrentCategory 的 setter 中设置,如下所示:

public int CurrentCategory
{       
  get { return _currentCategory; }

  set
  {
      _currentCategory = value;

      ProductsInCategory = DBAccess.GetProductsInCategory(_currentCategory).Tables["Products"].DefaultView;
      OnPropertyChanged("CurrentCategory");
  } 

}

以下是用于在 CurrentCategory 选择更改时重新连接 Current Product ItemsSource 的 xaml。

<dg:DataGridComboBoxColumn Header="Current Product"
    SelectedValueBinding="{Binding Path=CurrentProduct}"
    SelectedValuePath="ProductID"
    DisplayMemberPath="ProductName">          

  <dg:DataGridComboBoxColumn.ElementStyle>
   <Style TargetType="ComboBox">
      <Setter Property="ItemsSource" Value="{Binding Path=ProductsInCategory}" />
   </Style>
  </dg:DataGridComboBoxColumn.ElementStyle>

  <dg:DataGridComboBoxColumn.EditingElementStyle>
    <Style TargetType="ComboBox">
      <Setter Property="ItemsSource" Value="{Binding Path=ProductsInCategory}" />
    </Style>
  </dg:DataGridComboBoxColumn.EditingElementStyle>

</dg:DataGridComboBoxColumn>

【讨论】:

  • 您能否在答案中复制或引用链接的相关部分?随着时间的推移,链接往往会被删除。
  • @MarioTacke 完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
相关资源
最近更新 更多