如何在 DataGridView 中使用两种形式制作过滤器?

Posted

技术标签:

【中文标题】如何在 DataGridView 中使用两种形式制作过滤器?【英文标题】:How to make a filter in DataGridView with two forms? 【发布时间】:2021-11-01 09:23:06 【问题描述】:

我有 2 个 Windows 窗体。在第一个表单上,我有一个 DataGridView,在第二个表单上,我只有几个 checkListBoxes。

我发现这个问题类似于我的:Filtering datagridview from another form

它看起来与我的问题相似,但它并没有说明我如何从第二种形式中过滤信息。

另外,我已经问过一些关于这个项目的问题:How can I load in Windows Forms? (C#)

这有助于更好地理解这种情况。

我的想法是你必须在第二个表单上做一些标记,它现在正在保存你点击的内容,但我需要在 DGV 的第一个表单上获得这些点击。

问题是:如何做一个有两种形式的过滤器?

代码:

 private void button2_Click_2(object sender, EventArgs e)
    
        Form2 form2 = new Form2(this);
        form2.InitializeSecondForm();
        form2.Show();
     

 public void InitializeSecondForm()
    
        this.Height = Properties.Settings.Default.SecondFormHeight;
        this.Width = Properties.Settings.Default.SecondFormWidth;
        this.Location = Properties.Settings.Default.SecondFormLocation;
        this.collectionOfTags = Properties.Settings.Default.DICOMTagSettings;

        this.FormClosing += SecondFormClosingEventHandler;
        this.StartPosition = FormStartPosition.Manual;
     
 private void SecondFormClosingEventHandler(object sender, FormClosingEventArgs e)
    
        Properties.Settings.Default.SecondFormHeight = this.Height;
        Properties.Settings.Default.SecondFormWidth = this.Width;
        Properties.Settings.Default.SecondFormLocation = this.Location;
        Properties.Settings.Default.DICOMTagSettings = this.collectionOfTags;

        Properties.Settings.Default.Save();
     
 private void fileListDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
    

        DicomFileInfo dicomFile = new DicomFileInfo();

        DataGridView datas = new DataGridView();
        
        datas.DataSource = dicomFile;

        for(int i = 0; i < datas.Rows.Count; i++)
        
            DataGridViewLinkCell linkCell = new DataGridViewLinkCell();

            datas[2, i] = linkCell;
        
     

第二种形式的代码:

public partial class Form2 : Form

    StringCollection collectionOfTags = new StringCollection();
    public Form2()
    
        InitializeComponent();

        InitializeSecondForm();

        LoadSettings();
    

    
    private void LoadSettings()
    
        for (int i = 0; i < checkedListBox1.Items.Count; i++)
        
            var d = checkedListBox1.Items[i];
            if (collectionOfTags.Contains(d.ToString()))
            
                int index = checkedListBox1.Items.IndexOf(d);
                if (index != -1)
                    checkedListBox1.SetItemChecked(index, true);
            
        

        for (int i = 0; i < checkedListBox2.Items.Count; i++)
        
            var d = checkedListBox2.Items[i];
            if (collectionOfTags.Contains(d.ToString()))
            
                int index = checkedListBox2.Items.IndexOf(d);
                if (index != -1)
                    checkedListBox2.SetItemChecked(index, true);
            
        

        for (int i = 0; i < checkedListBox3.Items.Count; i++)
        
            var d = checkedListBox3.Items[i];
            if (collectionOfTags.Contains(d.ToString()))
            
                int index = checkedListBox3.Items.IndexOf(d);
                if (index != -1)
                    checkedListBox3.SetItemChecked(index, true);
            
        

        for (int i = 0; i < checkedListBox4.Items.Count; i++)
        
            var d = checkedListBox4.Items[i];
            if (collectionOfTags.Contains(d.ToString()))
            
                int index = checkedListBox4.Items.IndexOf(d);
                if (index != -1)
                    checkedListBox4.SetItemChecked(index, true);
            
        

        for (int i = 0; i < checkedListBox5.Items.Count; i++)
        
            var d = checkedListBox5.Items[i];
            if (collectionOfTags.Contains(d.ToString()))
            
                int index = checkedListBox5.Items.IndexOf(d);
                if (index != -1)
                    checkedListBox5.SetItemChecked(index, true);
            
        

        for (int i = 0; i < checkedListBox6.Items.Count; i++)
        
            var d = checkedListBox6.Items[i];
            if (collectionOfTags.Contains(d.ToString()))
            
                int index = checkedListBox6.Items.IndexOf(d);
                if (index != -1)
                    checkedListBox6.SetItemChecked(index, true);
            
        

    

    public void InitializeSecondForm()
    
        this.Height = Properties.Settings.Default.SecondFormHeight;
        this.Width = Properties.Settings.Default.SecondFormWidth;
        this.Location = Properties.Settings.Default.SecondFormLocation;
        this.collectionOfTags = Properties.Settings.Default.DICOMTagSettings;

        this.FormClosing += SecondFormClosingEventHandler;
        this.StartPosition = FormStartPosition.Manual;
    

    private void SecondFormClosingEventHandler(object sender, FormClosingEventArgs e)
    
        Properties.Settings.Default.SecondFormHeight = this.Height;
        Properties.Settings.Default.SecondFormWidth = this.Width;
        Properties.Settings.Default.SecondFormLocation = this.Location;
        Properties.Settings.Default.DICOMTagSettings = this.collectionOfTags;

        Properties.Settings.Default.Save();
    

    private void button1_Click(object sender, EventArgs e)
    
       
        Properties.Settings.Default.DICOMTagSettings.Clear();

        Properties.Settings.Default.DICOMTagSettings
.AddRange(checkedListBox1.CheckedItems.Cast<string>().ToArray());
        foreach (string s in Properties.Settings.Default.DICOMTagSettings)
        
            int index = checkedListBox1.Items.IndexOf(s);
            if (index != -1) checkedListBox1.SetItemChecked(index, true);

            for (int i = 0; i < checkedListBox1.Items.Count; i++)
            
            

        

        Properties.Settings.Default.DICOMTagSettings
.AddRange(checkedListBox2.CheckedItems.Cast<string>().ToArray());
        foreach (string t in Properties.Settings.Default.DICOMTagSettings)
        
            int index = checkedListBox2.Items.IndexOf(t);
            if (index != -1) checkedListBox2.SetItemChecked(index, true);
        

        Properties.Settings.Default.DICOMTagSettings
.AddRange(checkedListBox3.CheckedItems.Cast<string>().ToArray());
        foreach (string c in Properties.Settings.Default.DICOMTagSettings)
        
            int index = checkedListBox3.Items.IndexOf(c);
            if (index != -1) checkedListBox3.SetItemChecked(index, true);
        

        Properties.Settings.Default.DICOMTagSettings
.AddRange(checkedListBox4.CheckedItems.Cast<string>().ToArray());
        foreach (string a in Properties.Settings.Default.DICOMTagSettings)
        
            int index = checkedListBox4.Items.IndexOf(a);
            if (index != -1) checkedListBox4.SetItemChecked(index, true);
        

        Properties.Settings.Default.DICOMTagSettings
.AddRange(checkedListBox5.CheckedItems.Cast<string>().ToArray());
        foreach (string k in Properties.Settings.Default.DICOMTagSettings)
        
            int index = checkedListBox5.Items.IndexOf(k);
            if (index != -1) checkedListBox5.SetItemChecked(index, true);
        

        Properties.Settings.Default.DICOMTagSettings
 .AddRange(checkedListBox6.CheckedItems.Cast<string>().ToArray());
        foreach (string q in Properties.Settings.Default.DICOMTagSettings)
        
            int index = checkedListBox6.Items.IndexOf(q);
            if (index != -1) checkedListBox6.SetItemChecked(index, true);
        
        this.Close();
    

【问题讨论】:

所以您有 2 个带有 2 个不同数据源的表单窗口和另一个您可以点击一些复选框来过滤显示在 2 个表单上的数据? @FlorianSchmidinger 我只有 2 个表格。在第一个表单上,我可以单击文件按钮,然后将显示第二个表单。在第二个表单上,您可以过滤,您需要在 DataGridView 中的第一个表单上查看哪些项目。 我看到图片很有帮助 您希望结果网格在您在第二个表单中打勾时在第一个表单上动态更改,还是您会单击“确定”然后执行过滤?您期待什么样的程序流程?不同类别的过滤器将如何组合? “OR 之内,AND 之间?” 链接回答为您指明方向。您需要在表单之间进行引用。 【参考方案1】:

您需要一种将数据从一个对象发送到另一个对象的方法。有很多可能性,但最简单的方法是实现观察者模式或利用事件,这是实现观察者模式的最简单形式。

就像您从表单订阅 Buttons clickevent 一样,您也可以自己公开事件并使用相应的 eventargs 将数据发送到订阅您的事件的任何内容:

public class Form1 // ignore class names it's just to demonstrate =)

    // ... other code

    public void PickTags_Click(object sender, EventArgs args)
    
        // i suppose you instanciate the form here...
    
        var filterForm = new FormWithFilters();
    
        filterForm.FilterChanged += OnFilterChanged; // here you subscribe
        filterForm.Show();
     

    public void OnFilterChanged(object sender, FilterEventArgs args)
    
        // ... apply your filter
    


public class FormWithFilters

    // ... other code
    
    public void YourUiHandler(object sender, EventArgs args)
    
        // collect the data for the filter
        
        var eventArgs = new FilterEventArgs
        
            // assign your Properties for the subscribers to consume
        ;
        
        FilterChanged?.Invoke(this, eventArgs); // notify subscribers
    
    
    
    public event EventHandler<FilterEventArgs> FilterChanged; // your very own event


public class FilterEventArgs : EventArgs

    // add whatever properties you need to communicate what has to be filtered...

【讨论】:

【参考方案2】:

不清楚“何时”您要更新表单 1 中的网格。有超过 40 个选项供用户选择,那么我认为您会在用户单击表单上的“确定”按钮时更新网格2. 在这种情况下,您可以对表单 2 使用 ShowDialog,在表单 2 关闭后,您的代码应该仍然能够获取表单 2 中的任何“公共”变量。因此,如果您将 CheckListBox(s ) 在表格 2“公开”中,然后您可以在表格 1 中检查它们,如下所示。

private void buttonToOpenForm2_Click(object sender, EventArgs e) 
  Form2 f2 = new Form2();
  f2.ShowDialog();
  StringBuilder sb = new StringBuilder();
  sb.AppendLine("Checked Options are: ... ");
  for (int i = 0; i < f2.checkedListBox1.Items.Count; i++) 
    sb.AppendLine("Option: " + f2.checkedListBox1.Items[i].ToString());
    sb.AppendLine("          " + (f2.checkedListBox1.GetItemChecked(i) ? " Is" : "Is Not") + " Checked");
  
  textBox1.Text = sb.ToString();

显然,如果表单 2 未将 CheckedListBoxes 公开,那么您将无法在表单 1 中看到它们。在表单 2 的设计器中……选择 CheckListBox(s) 并更改 @987654328 @属性到true

编辑...

试试下面不完整的伪代码。我创建了一个“全局”List&lt;string&gt;collectionOfTagsMaster,它保留了所有标签的列表。当第二个 from 关闭时,代码会创建一个包含所有标签的新列表,然后循环通过 form2 上的 CheckedListBox 框。如果未选中标签,则我们从curTags 标签列表中删除该标签。如果标签被选中,那么我们将标签留在列表中。

之后,一个简单的循环遍历网格中的所有列以将其设置为可见或不可见,具体取决于其列名是否包含在 curTags 集合中。在我的小型测试中,使用带有数据表数据源的网格按预期工作。

List<string> collectionOfTagsMaster = new List<string>();
// fill list with all tags

private void buttonToOpenForm2_Click(object sender, EventArgs e) 
  Form2 f2 = new Form2();
  f2.ShowDialog();
  List<string> curTags = new List<string>(collectionOfTagsMaster);
  for (int i = 0; i < f2.checkedListBox1.Items.Count; i++) 
    if (!f2.checkedListBox1.GetItemChecked(i)) 
      curTags.Remove(f2.checkedListBox1.Items[i].ToString());
    
  
  foreach (DataGridViewColumn column in dataGridView1.Columns) 
    if (curTags.Contains(column.Name)) 
      column.Visible = true;
    
    else 
      column.Visible = false;
    
  

最后,你能解释一下fileListDataGridView_CellContentClick事件中的代码吗?它看起来很奇怪,似乎什么也没做。你能解释一下代码应该做什么吗?

【讨论】:

但在我的情况下,您必须检查在第二种形式中单击了哪个,然后您必须只显示第一种形式中的那些。你的回答很有用,但对我来说不是。 你是什么意思... ”...您必须检查在第二种形式中单击了哪个...” ...? … 我们有复选框,我们可以点击其中的一些,这意味着我们可以选择一些参数。像您在第二个表格中显示的那些参数。当您在第二个表单上按确定时,它应该在第一个表单上仅显示我们选择的那些参数。我添加了这些表格的图片,它应该会有所帮助。 是的,没错,但是当我们知道哪些框被选中时,我们只需要在第一个表单上显示这些标签。您的解决方案已接近最终解决方案,但无法帮助我在第一个表单标签上显示。 嗯……也许我遗漏了什么……你问题的倒数第二句……”我的想法是你必须在第二个表格上打上一些标记,它现在正在保存你的内容点击,但我需要在 DGV 的第一个表单上获得这些点击。” ...我的回答应该在这方面有所帮助。然后最后一句……“问题是:如何做一个有两种形式的过滤器?”……? ......我可能错过了你所说的“过滤器”和“两种形式”的意思......我假设从 from2 上的未选中框“过滤”掉 form1 的网格列。

以上是关于如何在 DataGridView 中使用两种形式制作过滤器?的主要内容,如果未能解决你的问题,请参考以下文章

一π等于多少弧度

如何给参考文献排序?

将具有不同数据源的 DataGridViewComboBoxCell 添加到 DataGridView

如何实现DataGridView刷新数据?

c# 如何改变datagridview里的字体颜色

c#中,excel表格内容展现在datagridview1中,如何实现?