DataGridView DataGridViewButtonColumn不会注意到一个真正的按钮

本文关键字:一个 按钮 DataGridViewButtonColumn 注意到 DataGridView | 更新日期: 2023-09-27 18:15:55

谢谢你看我的问题。我有一个对象叫做UIChoice

namespace uitest
{
  public class UIChoice
  {
      public String name {get; set;}
      public Button yes { get; set; }      
  }
}

那么我有一个Form1和一个DataGridView(我叫它grdChoice)像这样

namespace uitest
{
  public class Form1 : Form
  {
    public BindingList<UIChoice> Choices = new BindingList<UIChoice>();
    public Form1 ()
    {
        InitializeComponent();
        DataGridViewTextBoxColumn colName = new DataGridViewTextBoxColumn();
        colName.HeaderText = "Name:";
        colName.Name = "yestext";
        colName.DataPropertyName = "name";
        grdChoice.Columns.Add(colName);
        DataGridViewButtonColumn colYes = new DataGridViewButtonColumn();
        colYes.HeaderText = "Yes:";
        colYes.Name = "yesbutton";
        colYes.DataPropertyName = "yes";
        colYes.FlatStyle = FlatStyle.Popup;
        grdChoice.Columns.Add(colYes);
        grdChoice.DataSource = Choices;
        grdChoice.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
        grdChoice.Show();  
        FillData();
    }
    private void FillData()
    {
        UIChoice myChoice = new UIChoice();
        Button Yes = new Button();
        Yes.Click += ((sender, args) =>
        {
                MessageBox.Show("try this yes works");
        });
        Yes.Text = "yes";
        myChoice.name = "try this";
        myChoice.yes = Yes;
        Choices.Add(myChoice);
        UIChoice myChoiceA = new UIChoice();
        Button YesA = new Button();
        YesA.Click += ((sender, args) =>
        {
                MessageBox.Show("try A yes works");
        });
        YesA.Text = "yes";
        myChoiceA.name = "try A";
        myChoiceA.yes = YesA;
        Choices.Add(myChoiceA);
    }
  }
}

应该发生的事情(在我的想象中)是DataGridView应该注意到它是DataGridViewButtonColumn,并注意到它已经被赋予了一个按钮并使用它。但事实并非如此。对我来说,问题是这是一个替换代码。在现实生活中,UIChoice对象是用方法强化的,DataGridView(最初)仅仅是为了取代一个水平递增按钮的手摇面板(变得太"庞大"),可悲的是,正如我所写的,DataGridView不起作用,即当我构造一个BindingList对象时,它似乎没有"注意"或"关心"我给它一个按钮。我如何让DataGridView注意到我已经给它发送了它需要的Buttons ?

DataGridView DataGridViewButtonColumn不会注意到一个真正的按钮

关闭

按钮,希望在单元格值中。

但是你不能像那样点击它们

相反,您编写grdChoice.CellClick事件,可能像这样:

if (e.ColumnIndex == yourButtonColumnIndex )
{
   Button btn = gradesDataGridView[yourButtonColumnIndex , e.RowIndex].Value as Button;
   if (btn != null) buttons_Click(btn, null);
}

这将触发一个公共事件buttons_Click,您可以使用sender参数来识别按钮并调用适当的代码。

这可能是好的,但也许你宁愿看到正确的点击被自动触发…?

使用一点反射魔法(在CodeProject上找到),这也可以工作:

if (e.ColumnIndex == yourButtonColumnIndex )
{
   Button btn = gradesDataGridView[yourButtonColumnIndex , e.RowIndex].Value as Button;
   if (btn != null) 
   {
     var handler = (EventHandler)GetDelegate(btn, "EventClick");
     if (handler != null) btn.Invoke(handler);
   }
}

下面是修改后的代码,用于获取按钮的事件处理程序:

private static object GetDelegate(Control issuer, string keyName)
{
    // Get key value for a Click Event
    var key = typeof(Control)
        .GetField(keyName, BindingFlags.Static | BindingFlags.NonPublic | 
                               BindingFlags.FlattenHierarchy)
        .GetValue(null);
    var events = typeof(Component)
        .GetField("events", BindingFlags.Instance | BindingFlags.NonPublic)
        .GetValue(issuer);
    // Find the Find method and use it to search up listEntry for corresponding key
    var listEntry = typeof(EventHandlerList)
        .GetMethod("Find", BindingFlags.NonPublic | BindingFlags.Instance)
        .Invoke(events, new object[] { key });
    // Get handler value from listEntry 
    var handler = listEntry
        .GetType()
        .GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic)
        .GetValue(listEntry);
    return handler;
}

向CodeProject上的家伙致敬,Kostikov先生和匿名用户#2573523为控件添加了更改,而不是组件。

编辑我注意到按钮列没有文本。要显示单个按钮的文本,您需要像这样编写DataGridView_CellFormatting事件:

private void gradesDataGridView_CellFormatting(
                                 object sender, DataGridViewCellFormattingEventArgs e)
{
   if (e.ColumnIndex == yourBottonColumnIndex )
   {
     Button btn = gradesDataGridView[yourButtonColumnIndex , e.RowIndex].Value as Button;
     if (btn != null) e.Value = btn.Text;
   }
}

注意e.Value不是单元格。

谢谢你的回答,由于周末和远离工作,我实际上已经完成了这个4小时后张贴,但被要求等待8小时-尽管如此,你应该有点!:-)(我还借用了你对按钮文本显示的e.value部分的使用,因为它比我的更优雅!)

好的,所以,我个人,我通过意识到DataGridView CellClick (DataGridView sender).CurrentCell.Value实际上是(Button)来修复它。这就是我是如何做到的:(稍微阅读OP &

调整Form1构造函数的底部
grdChoice.DataSource = Verdicts;
grdChoice.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
grdChoice.CellClick += grdChoice_CellClick; //<-- add this line ***
grdChoice.Show();  

下一部分只监视任何单元格上的任何点击,如果它是一个按钮列,则人为地触发按钮

private void grdChoice_CellClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == grdChoice.Columns["yesbutton"].Index)
    {
        ((Button)((DataGridView)sender).CurrentCell.Value).PerformClick();
    }
}

最后一部分是显示按钮文本,我这样做了:

private void grdVerdict_CellFormat(object sender, DataGridViewCellFormattingEventArgs e)
{
   if (e.ColumnIndex == grdChoice.Columns["yesbutton"].Index)
   {
       e.Value = ((Button)grdChoice[e.ColumnIndex, e.RowIndex].Value).Text;
   }
}

与此处理程序

grdVerdict.CellFormatting += grdVerdict_CellFormat;  //<-- add this line near where the 3 stars are above***