4

我正在尝试使 gridview 的编辑功能更智能一些。

作为第一步,我希望当我为一行按编辑时, 所有带有DateTime数据的列都会有一个日期选择器而不是文本框,似乎我的尝试只能编辑后面的行,而不是当前显示的编辑项。

我的目标是将我正在编辑的行中的日期列更改为日期选择器。

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

4 回答 4

2

我会说这是错误的方法,您不应该在运行时使用 Control 类型在构建数据网格时您的 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。就是这样,我们现在没有任何编辑事件。

现在这对我们有用,但与在网上找到的随机样本一样,使用风险自负!

于 2013-01-09T13:19:32.193 回答
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>

[更新]

您还可以动态创建列。请检查以下代码:

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

}
于 2013-01-09T13:25:51.247 回答
0

看起来您的问题在于e.NewEditIndex不是正确的值,因为在该行实际进入编辑模式之前RowEditing触发了该事件。这意味着 的值将是您上次编辑的任何行的索引。如果我不得不猜测,我会说您是按顺序遍历行,所以您总是在修改“后面的行”纯属巧合。e.NewEditIndex

从文档中,您似乎可以通过访问该GridView.SelectedIndex属性来获取当前选定行的索引。如果要在编辑之前选择该行:

你可以改变:var row = ((GridView)sender).Rows[e.NewEditIndex].Cells;

到:var row = ((GridView)sender).Rows[(GridView)sender.SelectedIndex].Cells;

SetEditRow您还可以探索使用以下方法手动将行置于编辑模式:http: //msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.seteditrow.aspx

无论哪种方式,您都需要在调用RowEditing事件之前知道当前所在行的索引,或者使用方法强制该行进入编辑模式SetEditRow,这会将正确的索引传播到RowEditing事件中。

祝你好运。

于 2013-01-07T21:22:23.630 回答
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);
        }
    }

}

试试这个

于 2013-01-09T12:28:17.167 回答