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, он, кажется, не "замечает" или "не заботится", что я даю ему кнопку... как мне сделать DataGridView все равно, что я уже отправил Buttons это нужно?

2 ответа

Решение

Близко.

Кнопки, надеюсь, находятся в значениях ячеек.

Однако вы не можете щелкнуть их просто так.

Вместо этого вы код 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, чтобы различить кнопки и вызвать соответствующий код.

Это может быть хорошо, но, возможно, вы бы предпочли, чтобы правильные клики запускались автоматически..?

С небольшой Reflection Magic (найденной здесь на 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, г-ну Костикову и анонимному пользователю #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), Вот как я это сделал: (немного прочитайте ОП и отрегулируйте нижнюю часть конструктора 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***
Другие вопросы по тегам