简体   繁体   中英

Counting the number of "✓" in a column in my datagridview with C#

im really trying to figure out how to count "✓" this symbol in a column for a performance monitor. I really cannot figure out the code for this... i tried a lot of possible ways but no luck. In visual basic i managed to do it but in C#,i just cant figure it out.

Here are some code examples that i tried.

var count = dataGridView1.Rows.Cast<DataGridViewRow>()
    .Where(row => !(row.Cells[7].Value == null || row.Cells[7].Value == DBNull.Value))
    .Count();

txtSearch.Text = count.ToString();
int sum = 0;
for (int i = 0; i <= dataGridView1.Rows.Count(); i++)
{
    sum = int.Parse(dataGridView1.Rows[i].Cells[7].Value.ToString());
}
txtSearch.Text = sum.ToString();
txtSearch.Text = (from DataGridViewRow row in dataGridView1.Rows
        where row.Cells[7].FormattedValue.ToString() != string.Empty
        select Convert.ToInt32(row.Cells[7].FormattedValue)).Sum().ToString();

@demo Hello, sorry for lack of info, i kinda tried that is why is also sum, i need to count the number of times is ✓- this in that column and get the value in a textbox.

@igor im posting the vb code. also sry for the lack of info. Erros that i get.. usualy i get nothing. it just doesnt work...

Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
    Form15.Show()
    Dim colsum As Decimal
    Dim colsum2 As Decimal
    Dim colsum3 As Decimal
    Dim colsum4 As Decimal
    Dim colsum5 As Decimal
    Dim colsum6 As Decimal
    Dim colsum7 As Decimal
    Dim colsum8 As Decimal

    Dim a As Integer = 7
    Dim b As Integer = 8
    Dim c As Integer = 9
    Dim d As Integer = 10
    Dim x As Integer = 11
    Dim f As Integer = 12
    Dim g As Integer = 13
    Dim h As Integer = 14



    colsum = ((From Rows In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where Not Rows.IsNewRow AndAlso Rows.Cells(a).Value = "✓").Count / 20) * 100
    colsum2 = ((From Rows In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where Not Rows.IsNewRow AndAlso Rows.Cells(b).Value = "✓").Count / 20) * 100
    colsum3 = ((From Rows In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where Not Rows.IsNewRow AndAlso Rows.Cells(c).Value = "✓").Count / 20) * 100
    colsum4 = ((From Rows In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where Not Rows.IsNewRow AndAlso Rows.Cells(d).Value = "✓").Count / 20) * 100
    colsum5 = ((From Rows In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where Not Rows.IsNewRow AndAlso Rows.Cells(x).Value = "✓").Count / 20) * 100
    colsum6 = ((From Rows In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where Not Rows.IsNewRow AndAlso Rows.Cells(f).Value = "✓").Count / 20) * 100
    colsum7 = ((From Rows In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where Not Rows.IsNewRow AndAlso Rows.Cells(g).Value = "✓").Count / 20) * 100
    colsum8 = ((From Rows In DataGridView1.Rows.Cast(Of DataGridViewRow)() Where Not Rows.IsNewRow AndAlso Rows.Cells(h).Value = "✓").Count / 20) * 100


    Form15.Label9.Text = colsum
    Form15.Label10.Text = colsum2
    Form15.Label11.Text = colsum3
    Form15.Label12.Text = colsum4
    Form15.Label13.Text = colsum5
    Form15.Label14.Text = colsum6
    Form15.Label15.Text = colsum7
    Form15.Label16.Text = colsum8

    Form15.Chart1.Series("Machine-Load").Points.AddXY("Hard-Milling", Form15.Label9.Text)
    Form15.Chart1.Series("Machine-Load").Points.AddXY("Graphite Milling", Form15.Label10.Text)
    Form15.Chart1.Series("Machine-Load").Points.AddXY("Wire-Cut", Form15.Label11.Text)
    Form15.Chart1.Series("Machine-Load").Points.AddXY("Erosion", Form15.Label12.Text)
    Form15.Chart1.Series("Machine-Load").Points.AddXY("Drilling", Form15.Label13.Text)
    Form15.Chart1.Series("Machine-Load").Points.AddXY("Flat-Grinding", Form15.Label14.Text)
    Form15.Chart1.Series("Machine-Load").Points.AddXY("Profile Grinding", Form15.Label15.Text)
    Form15.Chart1.Series("Machine-Load").Points.AddXY("Laser Engraving", Form15.Label16.Text)
End Sub

In programming there is a tendency to separate the data (= model) from the way that this data is displayed (= view). This has the advantage that you can change the way that you display the data without having to change the model. So if you decide to display a checkbox instead of a check mark, your model does not have to change.

To transform the model to the view, an adapter class is needed: the ViewModel. Together these three classes are abbreviated MVVM. Consider to read some background about this.

In Winforms you can use the ViewModel by using the DataSource of the DataGridView.

If the data that you want display is very similar to the data in your model, you don't need a special display class. If the data is fairly different, it might be wise to create a special class for the Display dataSo if you want to Display Customers, you create a class DisplayCustomer:

class DisplayCustomer
{
    public Customer Customer {get; set;}  // the Customer from the model

    public int Id
    {
        get => this.Customer.Id,
        set => this.Customer.Id = value;
    }

    public string Name
    {
        get => this.Customer.Name,
        set => this.Customer.Name = value,
    }

    ... etc.

But again: if there is no difference between the displayed data and the model data, you don't need a separate class.

A good example is your Checkmark. If this is a Boolean in Customer, but a string Checkmark in DisplayCustomer, you will have something like this:

class Customer
{
    ...
    public bool IsSpecial {get; set;}
|

class DisplayCustomer
{
    ...
    private const string checkMark = "✓";
    public string IsSpecial
    {
        get => this.Customer.IsSpecial ? checkMark : String.Empty;
        set => this.Customer.IsSpecial = checkMark == value;
    }
 

In visual studio designer you will have added your columns. Use property DataGridViewColumn.DataPropertyName to define the name of the property that must be shown in the column. This can be done in the designer, or in the constructor:

class MyForm : Form
{
    public MyForm()
    {
        InitializeComponent();

        this.columnId.DataPropertyName = nameof(DisplayCustomer.Id);
        this.columnName.DataPropertyName = nameof(DisplayCustomer.Name);
        ...
        this.columnIsSpecial.DataPropertyName = nameof(DisplayCustomer.IsSpecial);
    }

To Display your Customers:

public BindingList<DisplayCustomer> DisplayedCustomers
{
    get => (BindingList<DisplayCustomer>)this.dataGridView1.DataSource;
    set => this.dataGridView1.DataSource = value;
}

public void DisplayCustomers()
{
    IEnumerable<Customer> customers = this.FetchCustomers();
    this.DisplayedCustomers = new BindingList<DisplayCustomer(
       customers.Select(customer => new DisplayCustomer {Customer = customer})
                .ToList());
}

That's all: two almost one liner functions make that your data is displayed, and if the operator Adds / Removes / Edits rows or cells, then the data is automatically updated.

For instance, after editing the operator presses the Apply Now button.

private void OnButtonApplyNow_Clicked(object sender, ...)
{
    IEnumerable<Customer> editedCustomers = this.DisplayedCustomers
        .Select(displayedCustomer => displayedCustomer.Customer);
    this.ProcessEditedCustomers(editedCustomers);
}

Counting your checkmarks is now fairly easy:

private int CountCheckMarks(IEnumerable<Customer> customers)
{
    return customers.Where(customer => customer.IsSpecial).Count();
}

or if you want a property:

private int CheckMarkCount => this.DisplayedCustomers
    .Where(customer => customer.IsSpecial).Count()

Some other improvements

Apart from property DisplayedCustomers, you can also create properties for the Current Customer and the Selected Customers.

public DisplayCustomer CurrentDisplayCustomer =>
    (DisplayCustomer) this.dataGridView1.CurrentRow?.DataBoundItem;

public Customer CurrentCustomer => this.CurrentDisplayCustomer?.Customer;

public IEnumerable<DisplayCustomer> SelectedDisplayCustomers =>
    this.dataGridView1.SelectedRows.Cast<DataGridViewRow>()
        .Select(row => row.DataBoundItem)
        .Cast<DisplayCustomer>();

Once again: only create a special DisplayCustomer class if you need to.

But I don't want to use the DataSource!

Some people prefer to directly access the DataGridViewCells. How about this:

private const string checkMark = "✓";

private IEnumerable<DataGridViewRow> CheckedRows => this.dataGridView1.Rows
    .Cast<DataGridViewRow>()
    .Where(row => row.Cells[this.columnIsSpecial.DisplayIndex].Value.ToString() == checkMark);

private int CheckedRowCount => this.CheckedRows.Count();

I made a special property CheckedRows, because I figured you might want to use this for other purposes then to just count them.

Thanks everyone for the help, i wish you all the best. i Solved my problem by counting the non-empty cells in my columns. maybe it helps somebody else and i will post the code

 int count = dataGridView1.Rows
           .Cast<DataGridViewRow>()
           .Select(row => (string)row.Cells["VCE600PRO"].Value)
            .Where(v => !string.IsNullOrEmpty(v))
           .Count();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM