在gridview中处理当前编辑的行

时间:2012-12-23 16:04:14

标签: c# asp.net

我正在尝试使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);
        }
    }
}

但似乎它编辑后面的行,我怎样才能编辑我当前正在编辑的内容?

4 个答案:

答案 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);

其中eventDateDataGridViewCalendarColumnprivate 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);
        }
    }

}

试试这个