it-swarm.asia

انقر بزر الماوس الأيمن فوق قائمة السياق لـ datagridview

لدي datagridview في تطبيق winform .NET. أود النقر بزر الماوس الأيمن على التوالي ولدي قائمة منبثقة. ثم أرغب في تحديد أشياء مثل النسخ أو التحقق من الصحة أو ما إلى ذلك

كيف يمكنني جعل A) قائمة منبثقة B) أوجد الصف الذي تم النقر عليه. أعلم أنه يمكنني استخدام selectIndex لكن يجب أن أكون قادرًا على النقر بزر الماوس الأيمن دون تغيير ما تم تحديده؟ الآن يمكنني استخدام الفهرس المحدد ، ولكن إذا كانت هناك طريقة للحصول على البيانات دون تغيير ما تم تحديده ، فسيكون ذلك مفيدًا.

99
user34537

يمكنك استخدام CellMouseEnter و CellMouseLeave لتتبع رقم الصف الذي يحوم الماوس فوقه حاليًا.

ثم استخدم كائن ContextMenu لعرض قائمة منبثقة مخصصة للصف الحالي.

إليك مثال سريع وقذّر على ما أعنيه ...

private void dataGridView1_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        ContextMenu m = new ContextMenu();
        m.MenuItems.Add(new MenuItem("Cut"));
        m.MenuItems.Add(new MenuItem("Copy"));
        m.MenuItems.Add(new MenuItem("Paste"));

        int currentMouseOverRow = dataGridView1.HitTest(e.X,e.Y).RowIndex;

        if (currentMouseOverRow >= 0)
        {
            m.MenuItems.Add(new MenuItem(string.Format("Do something to row {0}", currentMouseOverRow.ToString())));
        }

        m.Show(dataGridView1, new Point(e.X, e.Y));

    }
}
130
Stuart Helwig

رغم أن هذا السؤال قديم ، إلا أن الإجابات غير ملائمة. تحتوي قوائم السياق على الأحداث الخاصة بها على DataGridView. يوجد حدث لقائمة سياق الصف وقائمة سياق الخلية.

السبب في أن هذه الإجابات غير مناسبة هو أنها لا تأخذ في الحسبان مخططات العمليات المختلفة. قد لا تعمل خيارات إمكانية الوصول ، أو الاتصالات عن بُعد ، أو منفذ Metro/Mono/Web/WPF ، وستفشل اختصارات لوحة المفاتيح لأسفل إلى اليمين (مفتاح العالي + مفتاح العالي أو قائمة السياق).

يجب أن تتم معالجة اختيار الخلية عند النقر بزر الماوس الأيمن يدويًا. لا يحتاج عرض قائمة السياق إلى معالجة حيث يتم التعامل مع هذا بواسطة واجهة المستخدم.

هذا يحاكي تماما النهج المستخدم من قبل Microsoft Excel. إذا كانت الخلية جزءًا من نطاق محدد ، فلن يتغير تحديد الخلية ولا يتغير CurrentCell. إذا لم يكن كذلك ، فسيتم مسح النطاق القديم وتحديد الخلية وتصبح CurrentCell.

إذا لم تكن واضحًا في هذا ، CurrentCell فهي حيث تركز لوحة المفاتيح عند الضغط على مفاتيح الأسهم. Selected هو ما إذا كان جزءًا من SelectedCells. ستظهر قائمة السياق عند النقر بزر الماوس الأيمن كما يتم التعامل معها بواسطة واجهة المستخدم.

private void dgvAccount_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex != -1 && e.RowIndex != -1 && e.Button == System.Windows.Forms.MouseButtons.Right)
    {
        DataGridViewCell c = (sender as DataGridView)[e.ColumnIndex, e.RowIndex];
        if (!c.Selected)
        {
            c.DataGridView.ClearSelection();
            c.DataGridView.CurrentCell = c;
            c.Selected = true;
        }
    }
}

لا تُظهر اختصارات لوحة المفاتيح قائمة السياق افتراضيًا ، لذلك يتعين علينا إضافتها.

private void dgvAccount_KeyDown(object sender, KeyEventArgs e)
{
    if ((e.KeyCode == Keys.F10 && e.Shift) || e.KeyCode == Keys.Apps)
    {
        e.SuppressKeyPress = true;
        DataGridViewCell currentCell = (sender as DataGridView).CurrentCell;
        if (currentCell != null)
        {
            ContextMenuStrip cms = currentCell.ContextMenuStrip;
            if (cms != null)
            {
                Rectangle r = currentCell.DataGridView.GetCellDisplayRectangle(currentCell.ColumnIndex, currentCell.RowIndex, false);
                Point p = new Point(r.X + r.Width, r.Y + r.Height);
                cms.Show(currentCell.DataGridView, p);
            }
        }
    }
}

لقد أعدت صياغة هذا الرمز للعمل بشكل ثابت ، بحيث يمكنك نسخه ولصقه في أي حدث.

المفتاح هو استخدام CellContextMenuStripNeeded لأن هذا سيعطيك قائمة السياق.

إليك مثال يستخدم CellContextMenuStripNeeded حيث يمكنك تحديد قائمة السياق التي تريد إظهارها إذا كنت تريد أن يكون لديك قائمة مختلفة لكل صف.

في هذا السياق MultiSelectTrue و SelectionModeFullRowSelect. هذا فقط للمثال وليس القيد.

private void dgvAccount_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;

    if (e.RowIndex == -1 || e.ColumnIndex == -1)
        return;
    bool isPayment = true;
    bool isCharge = true;
    foreach (DataGridViewRow row in dgv.SelectedRows)
    {
        if ((string)row.Cells["P/C"].Value == "C")
            isPayment = false;
        else if ((string)row.Cells["P/C"].Value == "P")
            isCharge = false;
    }
    if (isPayment)
        e.ContextMenuStrip = cmsAccountPayment;
    else if (isCharge)
        e.ContextMenuStrip = cmsAccountCharge;
}

private void cmsAccountPayment_Opening(object sender, CancelEventArgs e)
{
    int itemCount = dgvAccount.SelectedRows.Count;
    string voidPaymentText = "&Void Payment"; // to be localized
    if (itemCount > 1)
        voidPaymentText = "&Void Payments"; // to be localized
    if (tsmiVoidPayment.Text != voidPaymentText) // avoid possible flicker
        tsmiVoidPayment.Text = voidPaymentText;
}

private void cmsAccountCharge_Opening(object sender, CancelEventArgs e)
{
    int itemCount = dgvAccount.SelectedRows.Count;
    string deleteChargeText = "&Delete Charge"; //to be localized
    if (itemCount > 1)
        deleteChargeText = "&Delete Charge"; //to be localized
    if (tsmiDeleteCharge.Text != deleteChargeText) // avoid possible flicker
        tsmiDeleteCharge.Text = deleteChargeText;
}

private void tsmiVoidPayment_Click(object sender, EventArgs e)
{
    int paymentCount = dgvAccount.SelectedRows.Count;
    if (paymentCount == 0)
        return;

    bool voidPayments = false;
    string confirmText = "Are you sure you would like to void this payment?"; // to be localized
    if (paymentCount > 1)
        confirmText = "Are you sure you would like to void these payments?"; // to be localized
    voidPayments = (MessageBox.Show(
                    confirmText,
                    "Confirm", // to be localized
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Warning,
                    MessageBoxDefaultButton.Button2
                   ) == DialogResult.Yes);
    if (voidPayments)
    {
        // SQLTransaction Start
        foreach (DataGridViewRow row in dgvAccount.SelectedRows)
        {
            //do Work    
        }
    }
}

private void tsmiDeleteCharge_Click(object sender, EventArgs e)
{
    int chargeCount = dgvAccount.SelectedRows.Count;
    if (chargeCount == 0)
        return;

    bool deleteCharges = false;
    string confirmText = "Are you sure you would like to delete this charge?"; // to be localized
    if (chargeCount > 1)
        confirmText = "Are you sure you would like to delete these charges?"; // to be localized
    deleteCharges = (MessageBox.Show(
                    confirmText,
                    "Confirm", // to be localized
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Warning,
                    MessageBoxDefaultButton.Button2
                   ) == DialogResult.Yes);
    if (deleteCharges)
    {
        // SQLTransaction Start
        foreach (DataGridViewRow row in dgvAccount.SelectedRows)
        {
            //do Work    
        }
    }
}
73
ShortFuse

استخدم الحدث CellMouseDown على DataGridView. من وسيطات معالج الأحداث ، يمكنك تحديد الخلية التي تم النقر فوقها. باستخدام الأسلوب PointToClient() على DataGridView ، يمكنك تحديد الموضع النسبي للمؤشر إلى DataGridView ، حتى تتمكن من القائمة المنبثقة في الموقع الصحيح.

(توفر لك المعلمة DataGridViewCellMouseEvent فقط X و Y بالنسبة للخلية التي نقرت عليها ، وهي ليست سهلة الاستخدام لإظهار قائمة السياق.

هذا هو الرمز الذي استخدمته للحصول على موضع الماوس ، ثم اضبط موضع DataGridView:

var relativeMousePosition = DataGridView1.PointToClient(Cursor.Position);
this.ContextMenuStrip1.Show(DataGridView1, relativeMousePosition);

يبدو معالج الأحداث بأكمله كما يلي:

private void DataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
    // Ignore if a column or row header is clicked
    if (e.RowIndex != -1 && e.ColumnIndex != -1)
    {
        if (e.Button == MouseButtons.Right)
        {
            DataGridViewCell clickedCell = (sender as DataGridView).Rows[e.RowIndex].Cells[e.ColumnIndex];

            // Here you can do whatever you want with the cell
            this.DataGridView1.CurrentCell = clickedCell;  // Select the clicked cell, for instance

            // Get mouse position relative to the vehicles grid
            var relativeMousePosition = DataGridView1.PointToClient(Cursor.Position);

            // Show the context menu
            this.ContextMenuStrip1.Show(DataGridView1, relativeMousePosition);
        }
    }
}
43
Matt
  • ضع قائمة سياق في النموذج الخاص بك ، وقم بتسميته ، واضبط التسميات التوضيحية وما إلى ذلك باستخدام المحرر المضمن
  • اربطها بشبكتك باستخدام خاصية الشبكة ContextMenuStrip
  • لشبكتك ، قم بإنشاء حدث للتعامل مع CellContextMenuStripNeeded
  • يحتوي Event Args e على خصائص مفيدة e.ColumnIndex ، e.RowIndex.

أعتقد أن e.RowIndex هو ما تطلبه.

الاقتراح: عندما يتسبب المستخدم في إطلاق الحدث الخاص بك CellContextMenuStripNeeded ، استخدم e.RowIndex للحصول على بيانات من شبكتك ، مثل المعرّف. تخزين المعرف كعنصر علامة حدث القائمة.

الآن ، عندما ينقر المستخدم فعليًا على عنصر القائمة ، استخدم خاصية Sender لجلب العلامة. استخدم العلامة ، التي تحتوي على المعرف الخاص بك ، للقيام بالإجراء الذي تحتاجه.

37
ActualRandy

ببساطة اسحب مكون ContextMenu أو ContextMenuStrip إلى النموذج الخاص بك وقم بتصميمه بصريًا ، ثم قم بتعيينه إلى الخاصية ContextMenu أو ContextMenuStrip لعنصر التحكم المطلوب.

4
Captain Comic

بالنسبة إلى موضع قائمة السياق ، وجدت y المشكلة التي احتجت إليها لتكون مرتبطة بـ DataGridView ، والحدث الذي احتجت إلى استخدامه يعطي poistion بالنسبة للخلية التي تم النقر فوقها. لم أجد حلاً أفضل لذلك قمت بتنفيذ هذه الوظيفة في فئة المشاعات ، لذلك أسميها من أي مكان أحتاج إليه.

تم اختباره بشكل جيد ويعمل بشكل جيد. أتمنى أن تجدها مفيدة.

    /// <summary>
    /// When DataGridView_CellMouseClick ocurs, it gives the position relative to the cell clicked, but for context menus you need the position relative to the DataGridView
    /// </summary>
    /// <param name="dgv">DataGridView that produces the event</param>
    /// <param name="e">Event arguments produced</param>
    /// <returns>The Location of the click, relative to the DataGridView</returns>
    public static Point PositionRelativeToDataGridViewFromDataGridViewCellMouseEventArgs(DataGridView dgv, DataGridViewCellMouseEventArgs e)
    {
        int x = e.X;
        int y = e.Y;
        if (dgv.RowHeadersVisible)
            x += dgv.RowHeadersWidth;
        if (dgv.ColumnHeadersVisible)
            y += dgv.ColumnHeadersHeight;
        for (int j = 0; j < e.ColumnIndex; j++)
            if (dgv.Columns[j].Visible)
                x += dgv.Columns[j].Width;
        for (int i = 0; i < e.RowIndex; i++)
            if (dgv.Rows[i].Visible)
                y += dgv.Rows[i].Height;
        return new Point(x, y);
    }
3
Gers0n

اتبع الخطوات:

  1. أنشئ قائمة سياق مثل:  Sample context menu 

  2. يحتاج المستخدم إلى النقر بزر الماوس الأيمن على الصف للحصول على هذه القائمة. نحن بحاجة إلى معالجة الحدث _MouseClick وحدث _CellMouseDown.

selectBiodataid هو المتغير الذي يحتوي على معلومات الصف المحدد.

هنا هو الكود:

private void dgrdResults_MouseClick(object sender, MouseEventArgs e)
{   
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
    {                      
        contextMenuStrip1.Show(Cursor.Position.X, Cursor.Position.Y);
    }   
}

private void dgrdResults_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
    //handle the row selection on right click
    if (e.Button == MouseButtons.Right)
    {
        try
        {
            dgrdResults.CurrentCell = dgrdResults.Rows[e.RowIndex].Cells[e.ColumnIndex];
            // Can leave these here - doesn't hurt
            dgrdResults.Rows[e.RowIndex].Selected = true;
            dgrdResults.Focus();

            selectedBiodataId = Convert.ToInt32(dgrdResults.Rows[e.RowIndex].Cells[1].Value);
        }
        catch (Exception)
        {

        }
    }
}

وسيكون الإخراج:

 Final output 

3
Kshitij Jhangra