Кнопка Gridview в TemplateField срабатывает только при втором нажатии
Я провел некоторый поиск, прежде чем спрашивать, и хотя этот пост близок, он не работает для моего сценария.
Я обнаружил, что кнопка "удалить" в моем поле шаблона, кажется, срабатывает, но событие щелчка не срабатывает. Тем не менее, второй раз, когда вы нажимаете кнопку, она работает, как ожидалось.
Итак, нарушая код, я связываю свои данные с GridView
, используя `SqlDataSource.
Событие загрузки моей страницы начинается следующим образом:
if (!Page.IsPostBack)
{
externalUserDataSource.ConnectionString = "some connection string";
}
Мой источник данных выглядит следующим образом:
<asp:SqlDataSource ID="externalUserDataSource" runat="server"
ConflictDetection="CompareAllValues" SelectCommand="uspGetExternalUsersByTeam"
SelectCommandType="StoredProcedure" ProviderName="System.Data.SqlClient">
<SelectParameters>
<asp:SessionParameter Name="TeamID" SessionField="TeamID" Type="Int32" />
</SelectParameters>
</asp:SqlDataSource>
А это мой GridView
разметка:
<asp:GridView ID="gridView" runat="server" AutoGenerateColumns="False"
BackColor="White" BorderColor="#3366CC" BorderStyle="None" BorderWidth="1px"
CellPadding="4" DataKeyNames="LoginID" DataSourceID="externalUserDataSource"
EnableModelValidation="True" OnRowDataBound="GridViewRowDataBound" TabIndex="3">
<HeaderStyle BackColor="#003399" Font-Bold="True" ForeColor="White" />
<FooterStyle BackColor="#99CCCC" ForeColor="#003399" />
<PagerStyle BackColor="#99CCCC" ForeColor="#003399" HorizontalAlign="Left" />
<RowStyle BackColor="LightGoldenrodYellow" />
<SelectedRowStyle BackColor="#009999" Font-Bold="True" ForeColor="#CCFF99" />
<Columns>
<asp:BoundField DataField="RowID" HeaderText="Row ID" ReadOnly="True"
SortExpression="RowID" Visible="False" />
<asp:BoundField DataField="LoginID" HeaderText="Login ID" ReadOnly="True"
SortExpression="LoginID" Visible="False" />
<asp:BoundField DataField="EmailAddress" HeaderText="Email Address"
ItemStyle-VerticalAlign="Bottom" ReadOnly="True" SortExpression="AssociateName"/>
<asp:BoundField DataField="TeamID" HeaderText="Team ID" ReadOnly="True"
SortExpression="TeamID" Visible="False" />
<asp:CheckBoxField DataField="HasFIAccess"
HeaderText="Has Access to<br />Funding<br/>Illustrator"
ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Bottom"
ReadOnly="True"/>
<asp:CheckBoxField DataField="HasALTAccess"
HeaderText="Has Access to<br />Asset Liability<br/>Tracker"
ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Bottom"
ReadOnly="True"/>
<asp:CheckBoxField DataField="HasFIAAccess"
HeaderText="Has Access to<br />Funding<br/>Illustrator App"
ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Bottom"
ReadOnly="True"/>
<asp:TemplateField>
<ItemTemplate>
<asp:Button runat="server" CssClass="additionsRow" ID="btnDeleteExternalUser" OnClick="DeleteExtUserButtonClick"
CausesValidation="False" Text="Delete"
CommandArgument='<%#Eval("TeamID") + "," + Eval("LoginID") + "," + Eval("EmailAddress") + "," + Eval("HasALTAccess")%>'/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Итак, вы можете видеть, что я передаю некоторую информацию в кнопке, которая используется в событии, чтобы убедиться, что правильные данные удалены (поэтому я не могу использовать ButtonField
, как предлагается в ссылке выше).
Последняя часть головоломки это GridView
Событие:
protected void GridViewRowDataBound(object sender,
GridViewRowEventArgs e)
{
// if rowtype is not data row...
if (e.Row.RowType != DataControlRowType.DataRow)
{
// exit with no further processing...
return;
}
// get the ID for the selected record...
var selectedId = DataBinder.Eval(e.Row.DataItem, "RowID").ToString();
// create unique row ID...
e.Row.ID = string.Format("ExtUserRow{0}", selectedId);
// find the button delete for the selected row...
var deleteButton = (Button)e.Row.FindControl("btnDeleteExtUser");
// get the email address for the selected record...
var selectedUser = DataBinder.Eval(e.Row.DataItem, "EmailAddress").ToString();
// define the message text...
var messageText = string.Format("OK to delete {0}?",
selectedUser.Replace("'", "\\'"));
// add attribute to row delete action...
this.AddConfirmMessage(deleteButton, messageText);
}
куда AddConfirmMessage
просто присваивает атрибуту onclick элемент управления, чтобы гарантировать, что пользователь должен подтвердить удаление.
Теперь в каждом случае всплывает сообщение "ОК, чтобы удалить abc@xyz.com?', но, как указывалось ранее, событие, назначенное кнопке "удалить", не срабатывает, пока кнопка не будет нажата во второй раз.
Как ни странно, я взял этот код с другой страницы и изменил соответствующим образом, хотя там нет этой проблемы:
protected void DeleteExtUserButtonClick(object sender,
EventArgs e)
{
// get the buton which was clicked...
var button = (Button)sender;
// break the delimited array up...
string[] argumentArray = button.CommandArgument.Split(',');
// store the items from the array...
string teamId = argumentArray[0];
string loginId = argumentArray[1];
string emailAddress = argumentArray[2];
string hasAltAccess = argumentArray[3];
using (var conn = new SqlConnection(Utils.GetConnectionString()))
{
// create database command...
using (var cmd = new SqlCommand())
{
// set the command type...
cmd.CommandType = CommandType.StoredProcedure;
// set the name of the stored procedure to call...
cmd.CommandText = "uspDeleteExternalUser";
// create and add parameter to the collection...
cmd.Parameters.Add(new SqlParameter("@TeamId", SqlDbType.Int));
// assign the search value to the parameter...
cmd.Parameters["@TeamId"].Value = teamId;
// create and add parameter to the collection...
cmd.Parameters.Add(new SqlParameter("@LoginId", SqlDbType.VarChar, 50));
// assign the search value to the parameter...
cmd.Parameters["@LoginId"].Value = loginId;
// set the command connection...
cmd.Connection = conn;
// open the connection...
conn.Open();
// perform deletion of user...
cmd.ExecuteNonQuery();
}
}
// bind control to refresh content...
ExtUsersGrid.DataBind();
}
Я что-то упустил очевидное? Я счастлив изменить, если есть лучшие способы сделать это.
Изменить 1: Исходя из обсуждений ниже, я изменил следующее:
- Удалил
Onclick
свойство событияButtonItem
; - Установить
CommandName
а такжеCommandArgument
как предложено ниже, и обновилDataKeyNames
использовать RowID, который является уникальным идентификатором из данных; - Назначен
RowCommand
событие дляGridView
; - Присвоил код удаления
RowCommand
событие.
После этих изменений он все еще запускает код события строки при втором щелчке.
Редактировать 2: К вашему сведению - я удалил SqlDataSource
и связанный код / ссылки, и создал процедуру для заполнения набора данных, которая вызывается Page_Load
(внутри !Page.IsPostBack
скобки). Я начал вносить изменения ниже, чтобы использовать RowCommand
события, но они по-прежнему вызывали ту же проблему (т.е. кнопка будет срабатывать только при втором нажатии). Как используя RowCommand
означало преобразование BoundField
с ItemTemplate
s, я вернулся к событию нажатия кнопки, поскольку казалось бессмысленным вносить все эти изменения без выгоды. Если кто-то еще может помочь мне понять, почему он срабатывает только при втором щелчке, был бы признателен за ваш вклад.
2 ответа
Хорошо, расстраивает это из-за некоторого кода, который по неизвестным причинам работает в другом месте.
В событии DataBound было две строки кода:
// get the associate name for the selected record...
var selectedId = DataBinder.Eval(e.Row.DataItem, "RowID").ToString();
// create unique row ID...
e.Row.ID = string.Format("ExtUserRow{0}", selectedId);
Процесс применения идентификатора к строкам программно, кажется, разрушает связь между данными и событиями.
Удаляя эти две строки кода, он работает как положено.
Ну, вместо этого вы можете сделать что-то вроде этого.
Добавить CommandName
собственность на ваш GridView
как это. Также обратите внимание на изменения в CommandArgument
имущество:
<asp:TemplateField>
<ItemTemplate>
<asp:Button runat="server" CssClass="additionsRow" ID="btnDeleteExtUser"
CausesValidation="False" Text="Delete"
CommandName="OnDelete"
CommandArgument='<%# Container.DisplayIndex %>" '
</ItemTemplate>
</asp:TemplateField>
Код позади будет выглядеть примерно так. Обратите внимание, что я использую RowCommand
событие Gridview
,
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if(e.CommandName == "OnDelete")
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
// now you got the rowindex, write your deleting logic here.
int ID = Convert.ToInt32(myGrid.DataKeys[rowIndex]["ID"].Value);
// id will return you the id of the row you want to delete
TextBox tb = (TextBox)GridView1.Rows[rowIndex].FindControl("textboxid");
string text = tb.Text;
// This way you can find and fetch the properties of controls inside a `GridView`. Just that it should be within `ItemTemplate`.
}
}
Примечание: упоминание DataKeyNames="ID"
внутри вашего GridView
, "ID" - это столбец первичного ключа вашей таблицы.
Вы связываете GridView
на странице загрузки? Если так, то переместите его в !IsPostBack
блок как показано ниже:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GridView1.DataSource = yourDataSource;
GridView1.DataBind();
}
}