ড্যাটাগ্রিডভিউয়ের জন্য প্রসঙ্গ মেনুতে ডান ক্লিক করুন


116

নেট। উইনফর্ম অ্যাপে আমার একটি ডেটাগ্রিডভিউ রয়েছে। আমি একটি সারিতে ডান ক্লিক করতে এবং একটি মেনু পপ আপ করতে চাই। তারপরে আমি অনুলিপি, বৈধকরণ ইত্যাদির মতো জিনিসগুলি নির্বাচন করতে চাই

আমি কীভাবে এটিকে করব) মেনু পপ আপ বি) কোন সারিটি ডান ক্লিক করা হয়েছিল তা সন্ধান করুন। আমি জানি আমি সিলেক্ট ইন্ডেক্স ব্যবহার করতে পারতাম তবে নির্বাচিতটি পরিবর্তন না করে আমার ডান ক্লিক করতে সক্ষম হওয়া উচিত? এই মুহুর্তে আমি নির্বাচিত সূচকটি ব্যবহার করতে পারি তবে যদি নির্বাচিত যা পরিবর্তন না করে ডেটা পাওয়ার কোনও উপায় থাকে তবে তা কার্যকর।

উত্তর:


143

মাউস বর্তমানে ঘোরাফেরা করছে এমন সারি নম্বরটি ট্র্যাক করতে আপনি সেলমাউসএন্টার এবং সেলমাউসলিভ ব্যবহার করতে পারেন।

তারপরে পপআপ মেনুটি প্রদর্শন করার জন্য একটি কন্টেক্সটেমু অবজেক্টটি ব্যবহার করুন, বর্তমান সারির জন্য কাস্টমাইজড।

আমি কী বলতে চাইছি তার একটি দ্রুত এবং নোংরা উদাহরণ এখানে ...

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));

    }
}

6
সঠিক! এবং আপনার জন্য একটি নোট, var r = ডেটাগ্রিডভিউ 1. হিটটেষ্ট (ইএক্স, ইওয়াই); r.RowIndex তারপরে মাউস বা কারেন্টমাউস ওভার র ব্যবহার করে আরও ভাল কাজ করে

3
স্ট্রিংয়ে .ToString () ব্যবহার করে For
এমএস

19
এই পদ্ধতিটি পুরানো: একটি ডেটাগ্রিডভিউয়ের একটি সম্পত্তি রয়েছে: প্রসঙ্গমেনু। অপারেটরের ডান ক্লিকের সাথে সাথে প্রসঙ্গ মেনুটি খুলবে। সংশ্লিষ্ট কনটেক্সটমেনুওপেনিং ইভেন্টটি আপনাকে বর্তমান সেল বা নির্বাচিত কোষের উপর নির্ভর করে কী প্রদর্শিত হবে তা সিদ্ধান্ত নেওয়ার সুযোগ দেয়। অন্য উত্তরগুলির মধ্যে একটি দেখুন
হ্যারাল্ড কপুলস

4
সঠিক স্ক্রিনের সমন্বয় পেতে আপনার প্রসঙ্গের মেনুটি এটির মতো খুলতে হবে:m.Show(dataGridView1.PointToScreen(e.Location));
অলিভিয়ার জ্যাকট-ডেসকোম্বেস

আমি কীভাবে মেনুগুলিতে কোনও ফাংশন যুক্ত করব?
আলফা গ্যাব্রিয়েল ভি। টিম্বল

89

এই প্রশ্নটি পুরানো হলেও উত্তরগুলি সঠিক নয়। প্রসঙ্গ মেনুগুলির ডেটাগ্রিডভিউতে তাদের নিজস্ব ইভেন্ট রয়েছে। সারি প্রসঙ্গ মেনু এবং সেল প্রসঙ্গ মেনুয়ের জন্য একটি ইভেন্ট রয়েছে।

যে কারণে এই উত্তরগুলি যথাযথ নয় সেগুলি হ'ল তারা বিভিন্ন অপারেশন প্রকল্পের জন্য অ্যাকাউন্ট করে না। অ্যাক্সেসযোগ্যতার বিকল্পগুলি, রিমোট সংযোগগুলি বা মেট্রো / মনো / ওয়েব / ডাব্লুপিএফ পোর্টিং কাজ না করতে পারে এবং কীবোর্ড শর্টকাটগুলি ডানদিকে ব্যর্থ হয়ে যাবে (শিফট + এফ 10 বা প্রসঙ্গ মেনু কী)।

ডান মাউস ক্লিকে ঘর নির্বাচন ম্যানুয়ালি পরিচালনা করতে হবে। প্রসঙ্গ মেনুটি দেখানো হ্যান্ডেল করার দরকার নেই কারণ এটি ইউআই দ্বারা পরিচালিত হয়।

এটি মাইক্রোসফ্ট এক্সেল দ্বারা ব্যবহৃত পদ্ধতির সম্পূর্ণ নকল করে। যদি ঘরটি একটি নির্বাচিত ব্যাপ্তির অংশ হয় তবে ঘর নির্বাচন পরিবর্তন হয় না এবং হয় না 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);
            }
        }
    }
}

আমি এই কোডটি স্থিতিশীলভাবে কাজ করতে পুনরায় কাজ করেছি, যাতে আপনি এটিকে কোনও ইভেন্টে অনুলিপি করে আটকান can

কীটি ব্যবহার করা হ'ল এটি CellContextMenuStripNeededআপনাকে প্রসঙ্গ মেনু দেবে।

এখানে প্রতিটি উদাহরণ রয়েছে CellContextMenuStripNeededযেখানে আপনি সারি প্রতি আলাদা আলাদা থাকতে চান তবে কোন প্রসঙ্গ মেনুটি প্রদর্শন করতে হবে তা নির্দিষ্ট করতে পারেন।

এই প্রসঙ্গে MultiSelectহয় Trueএবং SelectionModeহয় FullRowSelect। এটি কেবল উদাহরণস্বরূপ এবং সীমাবদ্ধতার জন্য নয়।

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    
        }
    }
}

5
বিস্তৃত উত্তরের জন্য এবং অ্যাক্সেসিবিলিটি বিবেচনার জন্য +1 (এবং একটি 3 বছরের পুরানো প্রশ্নের উত্তর দেওয়ার জন্য)
gt

3
সম্মতি জানানো হয়েছে, এটি স্বীকৃতের চেয়ে অনেক ভাল (যদিও এর মধ্যে কারওর সাথে সত্যিই কোনও ভুল নেই) - এবং কীবোর্ড সমর্থন সহ আরও বেশি কুদোস, এমন কিছু লোক যা কেবল ভাবেননি বলে মনে হয়।
রিচার্ড মস

2
দুর্দান্ত উত্তর, সমস্ত নমনীয়তা দেয়: ক্লিক করা হয়েছে তার উপর নির্ভর করে বিভিন্ন প্রসঙ্গ মেনু। এবং ঠিক এক্সেল আচরণ
হ্যারাল্ড কপুলস

2
আমি এই পদ্ধতির অনুরাগী নই কারণ আমার সাধারণ ডেটাগ্রিডভিউয়ের সাথে আমি কোনও ডেটাসোর্স বা ভার্চুয়ালমড ব্যবহার করি না। The CellContextMenuStripNeeded event occurs only when the DataGridView control DataSource property is set or its VirtualMode property is true.
আরভো বোয়েন

47

CellMouseDownইভেন্টটি ব্যবহার করুন DataGridView। ইভেন্ট হ্যান্ডলার আর্গুমেন্ট থেকে আপনি নির্ধারণ করতে পারবেন কোন ঘরে ক্লিক করা হয়েছিল। PointToClient()ডেটাগ্রিডভিউতে পদ্ধতিটি ব্যবহার করে আপনি ডেটাগ্রিডভিউতে পয়েন্টারের আপেক্ষিক অবস্থান নির্ধারণ করতে পারেন, যাতে আপনি সঠিক স্থানে মেনুটি পপআপ করতে পারেন।

( DataGridViewCellMouseEventপ্যারামিটার শুধু আপনার দেয় Xএবং Yসেল আপনার ক্লিক, যা প্রসঙ্গ মেনু পপ আপ ব্যবহার করা সহজ হয় না আপেক্ষিক।)

এই কোডটি আমি মাউস অবস্থানটি পেতে ব্যবহার করি, তারপরে ডেটাগ্রিডভিউয়ের অবস্থানের জন্য সামঞ্জস্য করুন:

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);
        }
    }
}

1
আপনি (sender as DataGridView)[e.ColumnIndex, e.RowIndex];ঘরে সহজে কল করার জন্যও ব্যবহার করতে পারেন ।
Qsiris

চেক করা উত্তর একাধিক স্ক্রিনে সঠিকভাবে কাজ করে না তবে এই উত্তরটি কাজ করে।
ফুরকান একিঞ্চি

45
  • বিল্ট ইন সম্পাদক ব্যবহার করে আপনার ফর্মের একটি প্রসঙ্গ মেনু রাখুন, নাম দিন, ক্যাপশন সেট করুন
  • গ্রিড সম্পত্তি ব্যবহার করে এটি আপনার গ্রিডের সাথে লিঙ্ক করুন ContextMenuStrip
  • আপনার গ্রিডের জন্য, পরিচালনা করার জন্য একটি ইভেন্ট তৈরি করুন CellContextMenuStripNeeded
  • ইভেন্ট args ই দরকারী বৈশিষ্ট্য আছে e.ColumnIndex, e.RowIndex

আমি বিশ্বাস করি e.RowIndexআপনি এটিই চাইছেন is

পরামর্শ: যখন ব্যবহারকারী আপনার ইভেন্টটিকে CellContextMenuStripNeededআগুন জ্বালিয়ে দেয়, তখন e.RowIndexআপনার গ্রিড থেকে আইডির মতো ডেটা পেতে ব্যবহার করুন । মেনু ইভেন্টের ট্যাগ আইটেম হিসাবে আইডি সঞ্চয় করুন।

এখন, যখন ব্যবহারকারী আসলে আপনার মেনু আইটেমটি ক্লিক করেন, ট্যাগ আনার জন্য প্রেরক সম্পত্তিটি ব্যবহার করুন। আপনার প্রয়োজনীয় ক্রিয়াটি সম্পাদন করতে আপনার আইডি সহ ট্যাগটি ব্যবহার করুন।


5
আমি এটি যথেষ্ট upvote করতে পারবেন না। অন্যান্য উত্তরগুলি আমার কাছে সুস্পষ্ট ছিল তবে আমি বলতে পারি কনটেক্সট মেনুগুলির জন্য আরও অন্তর্নির্মিত সমর্থন ছিল (এবং কেবল ডেটাগ্রিডের জন্য নয়)। এটি সঠিক উত্তর।
জোনাথন উড

1
@ অ্যাক্টিওর্যান্ডি, ব্যবহারকারী যখন প্রকৃত প্রসঙ্গ মেনুতে ক্লিক করবে তখন আমি ট্যাগটি কীভাবে পাব? সেলকোনটেক্সমেনস্ট্রিপনিড ইভেন্টের অধীনে, আমার কাছে এরকম কিছু প্রসঙ্গ আছে en MenuStrip1.Tag = e.RowIndex;
এডউইন ইকেচুকু ওকনকভো

2
এই উত্তরটি প্রায় রয়েছে, তবে আমি আপনাকে গ্রিডের সম্পত্তি কনটেক্সটেনু স্ট্রিপের সাথে প্রসঙ্গ মেনুটি লিঙ্ক না করার পরামর্শ দিই। CellContextMenuStripNeededইভেন্ট হ্যান্ডলারটির পরিবর্তে ডু এর পরিবর্তে if(e.RowIndex >= 0){e.ContextMenuStrip = yourContextMenuInstance;}মেনুটি কেবলমাত্র একটি বৈধ সারিতে ডানদিকে প্রদর্শিত হবে (যেমন শিরোনাম বা খালি গ্রিড অঞ্চলে নয়)
জেমস এস

ঠিক যেমন এই খুব সহায়ক উত্তরের একটি মন্তব্য: CellContextMenuStripNeededকেবলমাত্র তখনই কাজ করে যদি আপনার ডিজিভি কোনও ডেটাসোর্সের সাথে আবদ্ধ থাকে বা যদি ভার্চুয়ালমডটি সত্যতে সেট করা থাকে। অন্যান্য ক্ষেত্রে আপনাকে সেই ট্যাগটি CellMouseDownইভেন্টে সেট করতে হবে । সেখানে নিরাপদে থাকার জন্য, DataGridView.HitTestInfoআপনি কোনও ঘরে রয়েছেন কিনা তা পরীক্ষা করতে মাউসডাউন ইভেন্ট হ্যান্ডলারে একটি সম্পাদন করুন।
লোকইজিনিয়ার

6

আপনার ফর্মের মধ্যে একটি কনটেক্সটেনু বা কনটেক্সটমেনু স্ট্রিপ উপাদানটিকে কেবল টেনে আনুন এবং এটি দৃশ্যত ডিজাইন করুন, তারপরে এটিকে আপনার পছন্দসই নিয়ন্ত্রণের কনটেক্সটেমেনু বা কনটেক্সটমেনু স্ট্রিপ সম্পত্তিতে অর্পণ করুন।


4

পদক্ষেপগুলো অনুসরণ কর:

  1. একটি প্রসঙ্গ মেনু তৈরি করুন: নমুনা প্রসঙ্গে মেনু

  2. এই মেনুটি পেতে ব্যবহারকারীকে সারিতে ডান ক্লিক করতে হবে। আমাদের _মাউস ক্লিক ইভেন্ট এবং _সেলমাউসডাউন ইভেন্টটি পরিচালনা করতে হবে।

নির্বাচিতবায়োডাটাইড হল পরিবর্তনশীল যা নির্বাচিত সারির তথ্য ধারণ করে।

কোডটি এখানে:

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)
        {

        }
    }
}

এবং আউটপুট হবে:

ফাইনাল আউটপুট


3

কনটেক্সট মেনুটির অবস্থানের জন্য, আপনি সমস্যাটি খুঁজে পেয়েছিলেন যে ডেটাগ্রিডভিউয়ের তুলনায় আমার এটির দরকার ছিল এবং আমি যে ইভেন্টটি ব্যবহার করতে চাইছিলাম সেটি ক্লিক করা ঘরের সাথে সম্পর্কিত পোয়েশন দেয়। আমি এর থেকে ভাল সমাধান খুঁজে পাইনি তাই আমি কমন্স ক্লাসে এই ফাংশনটি বাস্তবায়িত করেছি, তাই যেখানেই আমার প্রয়োজন সেখানে থেকে এটি কল করি।

এটি বেশ পরীক্ষিত এবং ভালভাবে কাজ করে। আশা করি এটি আপনার কাজে লাগবে.

    /// <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);
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.