我正在尝试使gridview的编辑功能更加智能。
作为第一步,当我按行编辑时,我想要
具有DateTime
数据的所有列都将具有日期选择器而不是文本框
似乎我的尝试只能编辑后面的行而不是当前显示的编辑项。
我的目标是将我正在编辑的行中的日期列更改为datepickers。
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
var row = ((GridView)sender).Rows[e.NewEditIndex].Cells;
for (int i = 0; i < row.Count; i++)
{
DateTime dtDate;
var res = DateTime.TryParse(row[i].Text, out dtDate);
if (res)
{
DatePickerControl.DatePicker text = new DatePickerControl.DatePicker();
text.CalendarDate = dtDate;
row[i].Controls.Clear();
row[i].Controls.Add(text);
}
}
}
但似乎它编辑后面的行,我怎样才能编辑我当前正在编辑的内容?
答案 0 :(得分:2)
我认为这是错误的方法,你不应该在运行时使用控件类型。在构建数据网格时,你的datagrid列应该是一个datepicker类型。
不幸的是,MS不提供一个,幸运的是他们确实提供了允许你这样做的框架:
你需要3件事,一件新的1)DataGridViewColumn
,一件新的2)DataGridViewTextBoxCell
,最后是实际的3)DateTimePicker编辑控件。
1:
public class DataGridViewCalendarColumn : DataGridViewColumn
{
public DataGridViewCalendarColumn()
: base(new DataGridViewCalendarCell())
{ }
public override DataGridViewCell CellTemplate
{
get { return base.CellTemplate; }
set
{
// Ensure that the cell used for the template is a CalendarCell.
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(DataGridViewCalendarCell)))
throw new InvalidCastException("Must be a DataGridViewCalendarCell");
base.CellTemplate = value;
}
}
}
2:
public class DataGridViewCalendarCell : DataGridViewTextBoxCell
{
public DataGridViewCalendarCell()
: base()
{
this.Style.Format = "d"; //short date style
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
//set the value of the editing control to the current cell value
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
DataGridViewCalendarControl ctl = DataGridView.EditingControl as DataGridViewCalendarControl;
//use default value if Value is null
if (this.Value == null || this.Value == DBNull.Value)
ctl.Value = (DateTime) this.DefaultNewRowValue;
else
ctl.Value = (DateTime) this.Value;
}
public override Type EditType
{
get
{
//return the type of control this cell uses
return typeof(DataGridViewCalendarControl);
}
}
public override Type ValueType
{
get
{
//return the type of the value that this cell contains
return typeof(DateTime);
}
}
public override object DefaultNewRowValue
{
get
{
//use today's date as the default value
return DateTime.Now;
}
}
}
3:
public class DataGridViewCalendarControl : DateTimePicker, IDataGridViewEditingControl
{
private DataGridView dataGridView;
private bool hasValueChanged = false;
int rowIndex;
public DataGridViewCalendarControl()
{
this.Format = DateTimePickerFormat.Short;
}
protected override void OnValueChanged(EventArgs eventargs)
{
//Notify the DataGridView that the value has changed
hasValueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
base.OnValueChanged(eventargs);
}
#region IDataGridViewEditingControl Members
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
this.Font = dataGridViewCellStyle.Font;
this.CalendarForeColor = dataGridViewCellStyle.ForeColor;
this.CalendarMonthBackground = dataGridViewCellStyle.BackColor;
}
public DataGridView EditingControlDataGridView
{
get { return dataGridView; }
set { dataGridView = value; }
}
public object EditingControlFormattedValue
{
get { return this.Value.ToShortDateString(); }
set
{
if (value is String)
try
{
this.Value = DateTime.Parse((String) value);
}
catch
{
this.Value = DateTime.Now;
}
}
}
public int EditingControlRowIndex
{
get { return rowIndex; }
set { rowIndex = value; }
}
public bool EditingControlValueChanged
{
get { return hasValueChanged; }
set { hasValueChanged = value; }
}
public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
{
//the DateTimePicker needs to handle the keys
switch (keyData & Keys.KeyCode)
{
case Keys.Left:
case Keys.Right:
case Keys.Up:
case Keys.Down:
case Keys.Home:
case Keys.End:
case Keys.PageUp:
case Keys.PageDown:
return true;
default:
return !dataGridViewWantsInputKey;
}
}
public Cursor EditingPanelCursor
{
get { return base.Cursor; }
}
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
return EditingControlFormattedValue;
}
public void PrepareEditingControlForEdit(bool selectAll)
{
//nowt needs doing...
}
public bool RepositionEditingControlOnValueChange
{
get { return false; }
}
然后在表单的Load事件:
eventDateDataGridViewCalendarColumn = new DataGridViewCalendarColumn();
eventDateDataGridViewCalendarColumn.DataPropertyName = "EventDate";
eventDateDataGridViewCalendarColumn.HeaderText = "Date";
//we've created the column, now insert it into the right location (after the ID and UserID)
this.tSEventsDataGridView.Columns.Insert(2, eventDateDataGridViewCalendarColumn);
//remove the original TextBox EventDate column added via VS
this.tSEventsDataGridView.Columns.RemoveAt(3);
其中eventDateDataGridViewCalendarColumn
是private DataGridViewCalendarColumn
。就是这样,我们现在已经有了任何编辑活动。
现在这对我们有用,但是一如既往地在网上找到随机样本,使用风险自负!
答案 1 :(得分:2)
即使方法不同,可能对您的方案有点过于简单,我建议您使用<asp:TemplateField />
来自定义编辑项模板(见下文)。当然,您可能还希望将我使用的<asp:Calendar />
控件替换为您的自定义DatePickerControl.DatePicker
控件。
<asp:GridView ID="GridView1" runat="server" OnRowEditing="GridView1_RowEditing">
<Columns>
<asp:TemplateField>
<EditItemTemplate>
<asp:Calendar runat="server" SelectedDate='<%# Eval("Date") %>'></asp:Calendar>
</EditItemTemplate>
<ItemTemplate>
<%# Eval("Date") %>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<强> [UPDATE] 强>
您还可以动态创建列。请检查以下代码:
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
GridView1.AutoGenerateColumns = false;
GridView1.AutoGenerateEditButton = true;
DataTable dataSource = new DataTable();
dataSource.Columns.Add("Id", typeof(int));
dataSource.Columns.Add("Date1", typeof(DateTime));
dataSource.Columns.Add("Date2", typeof(DateTime));
dataSource.Rows.Add(1, DateTime.Now, DateTime.Now.AddMonths(1));
dataSource.Rows.Add(2, DateTime.Now.AddMonths(2), DateTime.Now.AddMonths(3));
GridView1.Columns.Clear();
foreach (DataColumn column in dataSource.Columns)
{
if (column.DataType == typeof(DateTime))
{
var templateColumn = new TemplateField();
templateColumn.EditItemTemplate = new AddTemplateToGridView(ListItemType.EditItem, column.ColumnName);
templateColumn.ItemTemplate = new AddTemplateToGridView(ListItemType.Item, column.ColumnName);
templateColumn.HeaderText = column.ColumnName;
GridView1.Columns.Add(templateColumn);
}
else
{
var dataBoundColumn = new BoundField();
dataBoundColumn.DataField = column.ColumnName;
dataBoundColumn.HeaderText = column.ColumnName;
GridView1.Columns.Add(dataBoundColumn);
}
}
GridView1.DataSource = dataSource;
GridView1.DataBind();
}
public class AddTemplateToGridView : ITemplate
{
ListItemType _type;
string _colName;
public AddTemplateToGridView(ListItemType type, string colname)
{
_type = type;
_colName = colname;
}
public void InstantiateIn(Control container)
{
switch (_type)
{
case ListItemType.Item:
Label l = new Label();
l.DataBinding += l_DataBinding;
container.Controls.Add(l);
break;
case ListItemType.EditItem:
Calendar calendar = new Calendar();
calendar.DataBinding += l_DataBinding;
container.Controls.Add(calendar);
break;
}
}
void l_DataBinding(object sender, EventArgs e)
{
GridViewRow container;
object dataValue;
switch (sender.GetType().ToString())
{
case "System.Web.UI.WebControls.Label":
Label label = (Label)sender;
container = (GridViewRow)label.NamingContainer;
dataValue = DataBinder.Eval(container.DataItem, _colName);
if (dataValue != DBNull.Value)
{
label.Text = dataValue.ToString();
}
break;
//use the DatePickerControl.DatePicker type instead of calendar
case "System.Web.UI.WebControls.Calendar":
Calendar calendar = (Calendar)sender;
container = (GridViewRow)calendar.NamingContainer;
dataValue = DataBinder.Eval(container.DataItem, _colName);
if (dataValue != DBNull.Value)
{
calendar.SelectedDate = (DateTime)dataValue;
calendar.VisibleDate = (DateTime)dataValue;
}
break;
}
}
}
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
GridView1.EditIndex = e.NewEditIndex;
GridView1.DataBind();
}
}
答案 2 :(得分:0)
看起来您的问题是e.NewEditIndex
不正确,因为{<1}}事件在行实际进入编辑模式之前被触发。这意味着RowEditing
的值将是您上次编辑的任何行的索引。如果我不得不猜测,我会说你按顺序迭代这些行,所以你总是在修改“背后的行”,这纯属巧合。
从文档中,您可以通过访问e.NewEditIndex
属性来获取当前所选行的索引。如果要在编辑之前选择该行:
您可以更改:GridView.SelectedIndex
至:var row = ((GridView)sender).Rows[e.NewEditIndex].Cells;
您还可以使用var row = ((GridView)sender).Rows[(GridView)sender.SelectedIndex].Cells;
方法手动将行置于编辑模式:http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.seteditrow.aspx
无论哪种方式,您都需要在调用SetEditRow
事件之前知道当前行的索引,或者使用RowEditing
方法强制该行进入编辑模式,这将是将正确的索引传播到SetEditRow
事件中。
答案 3 :(得分:0)
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
bindgrid();
var row = ((GridView)sender).Rows[e.NewEditIndex].Cells;
for (int i = 0; i < row.Count; i++)
{
DateTime dtDate;
var res = DateTime.TryParse(row[i].Text, out dtDate);
if (res)
{
Calendar cal = new Calendar();
cal.SelectedDate = dtDate;
cal.VisibleDate = dtDate;
cal.DataBind();
//DatePickerControl.DatePicker text = new DatePickerControl.DatePicker();
//text.CalendarDate = dtDate;
row[i].Controls.Clear();
row[i].Controls.Add(cal);
}
}
}
试试这个