DataGridView DataGridViewButtonColumn没有注意到真正的Button

时间:2014-08-01 15:48:06

标签: c# winforms button datagridview datagridviewbuttoncolumn

感谢您查看我的问题。我有一个名为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对象时,它似乎没有“注意到”或“关心”我给它一个按钮..我该怎么做{ {1}}关心我已经发送了它需要的DataGridView吗?

2 个答案:

答案 0 :(得分:1)

关闭。

按钮,希望是在细胞价值观中。

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

而是编码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上找到here),这也有效:

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

}

以下是获取Buttons事件处理程序的修改代码:

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致敬,他们为Controls而不是Components添加了更改。

编辑我注意到按钮列没有文字。要显示各个按钮&#39;您需要为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不是cell.Value,只是显示的文本。

答案 1 :(得分:1)

谢谢你的回答,作为周末和工作之余,我在发布后的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***