使用 CustomButtonCallback 克隆引用类型属性
Clone reference type properties with CustomButtonCallback
我正在尝试关注 the DevExpress documentation example on cloning rows。基础知识很容易掌握,但是当您尝试克隆值类型以外的属性时,事情就变得棘手了。
第一次尝试/设置重现:
我已经将我的真实场景缩小到一个小的(大概)问题重现。以下是新创建的 ASP.NET 2.0 webforms 应用程序的全部内容。首先,假设这些域对象(在这里也可以兼作 DTO):
public class Qualification
{
public long Id { get; set; }
public string Title { get; set; }
}
public class Person
{
public long Id { get; set; }
public string Name { get; set; }
public Qualification Qualification { get; set; }
}
然后有两个 quick 'n dirty 数据源 类 像这样:
public class QualificationOds
{
public static List<Qualification> Qualificiations = new List<Qualification>
{
new Qualification { Id = 1, Title = "Doctore" }
};
public List<Qualification> GetRecords()
{
return Qualificiations;
}
}
public class PeopleOds
{
public List<Person> GetRecords()
{
return new List<Person>
{
new Person
{
Id = 1,
Name = "John Doe",
Qualification = QualificationOds.Qualificiations[0]
}
};
}
}
default.aspx 页面将首先 dx
注册到 DevExpress 命名空间:
<%@ Register Assembly="DevExpress.Web.ASPxGridView.v11.1, Version=11.1.11.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web.ASPxGridView" TagPrefix="dx" %>
<%@ Register Assembly="DevExpress.Web.ASPxEditors.v11.1, Version=11.1.11.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web.ASPxEditors" TagPrefix="dx" %>
并且有一个包含此代码的单一表格:
<asp:ObjectDataSource runat="server" ID="peopleDataSource" TypeName="DevxTest.PeopleOds" SelectMethod="GetRecords" />
<asp:ObjectDataSource runat="server" ID="qualificationsDataSource" TypeName="DevxTest.QualificationOds" SelectMethod="GetRecords" />
<dx:ASPxGridView
runat="server"
id="grvPeople"
KeyFieldName="Id"
DataSourceID="peopleDataSource"
OnCustomButtonCallback="grid_CustomButtonCallback"
OnInitNewRow="grid_InitNewRow">
<Columns>
<dx:GridViewCommandColumn>
<EditButton Visible="true" />
<CustomButtons>
<dx:GridViewCommandColumnCustomButton ID="Clone" Text="Clone" />
</CustomButtons>
</dx:GridViewCommandColumn>
<dx:GridViewDataTextColumn FieldName="Name" />
<dx:GridViewDataComboBoxColumn FieldName="Qualification.Id" >
<PropertiesComboBox
DataSourceID="qualificationsDataSource"
TextField="Title"
ValueField="Id"
ValueType="System.Int64" />
</dx:GridViewDataComboBoxColumn>
</Columns>
</dx:ASPxGridView>
后面的代码包含将一行克隆到新编辑表单的代码,基于上述 DevExpress 示例,如下所示:
private string[] fieldsToCopy = { "Name", "Id" };
private Hashtable valuesToClone;
protected void grid_CustomButtonCallback(object sender, ASPxGridViewCustomButtonCallbackEventArgs e)
{
if (e.ButtonID != "Clone") return;
valuesToClone = new Hashtable();
foreach (var fieldName in fieldsToCopy)
{
valuesToClone[fieldName] = grvPeople.GetRowValues(e.VisibleIndex, fieldName);
}
grvPeople.AddNewRow();
}
protected void grid_InitNewRow(object sender, DevExpress.Web.Data.ASPxDataInitNewRowEventArgs e)
{
if (valuesToClone == null) return;
foreach (string fieldName in fieldsToCopy)
{
e.NewValues[fieldName] = valuesToClone[fieldName];
}
}
这适用于 Name
属性,但不适用于 Qualification
属性。在页面上是这样显示的:
我也试过 "Qualification.Id"
和 "Qualification"
作为要复制的字段名称,但没有成功。无论如何,我很确定它应该像我的示例中那样 "Id"
,因为调试器仅针对这种情况显示正确的 GetRowValues
return 值。
第二次尝试/自定义代码来处理下拉菜单:
所以我想我需要一些自定义代码来为下拉菜单设置 NewValue。首先,我为 Qualification 列创建一个 EditItemTemplate
,如下所示:
<EditItemTemplate>
<dx:ASPxComboBox
runat="server"
ID="qualificationCombo"
DataSourceID="qualificationsDataSource"
TextField="Title"
ValueField="Id"
ValueType="System.Int64" />
</EditItemTemplate>
然后我将此代码添加到 grid_InitNewRow
:
// Attempt to set the combo box to a value:
var column = grvPeople.Columns["Qualification"] as GridViewDataColumn;
var comboBox = grvPeople.FindEditRowCellTemplateControl(column, "qualificationCombo") as ASPxComboBox;
var item = comboBox.Items.FindByValue(valuesToClone["Id"]);
item.Selected = true;
而且有效!但是,现在 Name
不再被克隆。它看起来像这样:
我不知道为什么,但是添加的代码有一个 side-effect 导致 NewValues
setter 方法失败。
底线:
底线相当简单:如何将 DevExpress 示例更改为也可以克隆引用类型属性的示例?
PS。我也 cross-posted my question on the DevExpress support forum.
您提到 "Qualification.Id"
不起作用,但您很可能在 EditItemTemplate
存在时尝试过。如果没有这样的模板,那么该代码实际上可以工作。
为了完整起见,将 fieldsToCopy
行代码更改为:
private string[] fieldsToCopy = { "Name", "Qualification.Id" };
并且确保没有EditItemTemplate
,然后就可以了。
或者,如果您出于某种原因无法使用 EditItemTemplate
,可以使用 "solution" 来确保该模板中的 ComboBox 绑定到克隆的值。确保使用以下代码挂接到 ComboBox 上的 OnDataBound
:
protected void qualificationCombo_DataBound(object sender, EventArgs e)
{
var column = grvPeople.Columns["Qualification"] as GridViewDataColumn;
var comboBox = grvPeople.FindEditRowCellTemplateControl(column, "qualificationCombo") as ASPxComboBox;
var item = comboBox.Items.FindByValue(valuesToClone["Id"]);
item.Selected = true;
}
这将正确地将 ComboBox 设置为克隆的值,同时还将 e.NewValues
用于普通字段的方法保持不变。
我正在尝试关注 the DevExpress documentation example on cloning rows。基础知识很容易掌握,但是当您尝试克隆值类型以外的属性时,事情就变得棘手了。
第一次尝试/设置重现:
我已经将我的真实场景缩小到一个小的(大概)问题重现。以下是新创建的 ASP.NET 2.0 webforms 应用程序的全部内容。首先,假设这些域对象(在这里也可以兼作 DTO):
public class Qualification
{
public long Id { get; set; }
public string Title { get; set; }
}
public class Person
{
public long Id { get; set; }
public string Name { get; set; }
public Qualification Qualification { get; set; }
}
然后有两个 quick 'n dirty 数据源 类 像这样:
public class QualificationOds
{
public static List<Qualification> Qualificiations = new List<Qualification>
{
new Qualification { Id = 1, Title = "Doctore" }
};
public List<Qualification> GetRecords()
{
return Qualificiations;
}
}
public class PeopleOds
{
public List<Person> GetRecords()
{
return new List<Person>
{
new Person
{
Id = 1,
Name = "John Doe",
Qualification = QualificationOds.Qualificiations[0]
}
};
}
}
default.aspx 页面将首先 dx
注册到 DevExpress 命名空间:
<%@ Register Assembly="DevExpress.Web.ASPxGridView.v11.1, Version=11.1.11.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web.ASPxGridView" TagPrefix="dx" %>
<%@ Register Assembly="DevExpress.Web.ASPxEditors.v11.1, Version=11.1.11.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" Namespace="DevExpress.Web.ASPxEditors" TagPrefix="dx" %>
并且有一个包含此代码的单一表格:
<asp:ObjectDataSource runat="server" ID="peopleDataSource" TypeName="DevxTest.PeopleOds" SelectMethod="GetRecords" />
<asp:ObjectDataSource runat="server" ID="qualificationsDataSource" TypeName="DevxTest.QualificationOds" SelectMethod="GetRecords" />
<dx:ASPxGridView
runat="server"
id="grvPeople"
KeyFieldName="Id"
DataSourceID="peopleDataSource"
OnCustomButtonCallback="grid_CustomButtonCallback"
OnInitNewRow="grid_InitNewRow">
<Columns>
<dx:GridViewCommandColumn>
<EditButton Visible="true" />
<CustomButtons>
<dx:GridViewCommandColumnCustomButton ID="Clone" Text="Clone" />
</CustomButtons>
</dx:GridViewCommandColumn>
<dx:GridViewDataTextColumn FieldName="Name" />
<dx:GridViewDataComboBoxColumn FieldName="Qualification.Id" >
<PropertiesComboBox
DataSourceID="qualificationsDataSource"
TextField="Title"
ValueField="Id"
ValueType="System.Int64" />
</dx:GridViewDataComboBoxColumn>
</Columns>
</dx:ASPxGridView>
后面的代码包含将一行克隆到新编辑表单的代码,基于上述 DevExpress 示例,如下所示:
private string[] fieldsToCopy = { "Name", "Id" };
private Hashtable valuesToClone;
protected void grid_CustomButtonCallback(object sender, ASPxGridViewCustomButtonCallbackEventArgs e)
{
if (e.ButtonID != "Clone") return;
valuesToClone = new Hashtable();
foreach (var fieldName in fieldsToCopy)
{
valuesToClone[fieldName] = grvPeople.GetRowValues(e.VisibleIndex, fieldName);
}
grvPeople.AddNewRow();
}
protected void grid_InitNewRow(object sender, DevExpress.Web.Data.ASPxDataInitNewRowEventArgs e)
{
if (valuesToClone == null) return;
foreach (string fieldName in fieldsToCopy)
{
e.NewValues[fieldName] = valuesToClone[fieldName];
}
}
这适用于 Name
属性,但不适用于 Qualification
属性。在页面上是这样显示的:
我也试过 "Qualification.Id"
和 "Qualification"
作为要复制的字段名称,但没有成功。无论如何,我很确定它应该像我的示例中那样 "Id"
,因为调试器仅针对这种情况显示正确的 GetRowValues
return 值。
第二次尝试/自定义代码来处理下拉菜单:
所以我想我需要一些自定义代码来为下拉菜单设置 NewValue。首先,我为 Qualification 列创建一个 EditItemTemplate
,如下所示:
<EditItemTemplate>
<dx:ASPxComboBox
runat="server"
ID="qualificationCombo"
DataSourceID="qualificationsDataSource"
TextField="Title"
ValueField="Id"
ValueType="System.Int64" />
</EditItemTemplate>
然后我将此代码添加到 grid_InitNewRow
:
// Attempt to set the combo box to a value:
var column = grvPeople.Columns["Qualification"] as GridViewDataColumn;
var comboBox = grvPeople.FindEditRowCellTemplateControl(column, "qualificationCombo") as ASPxComboBox;
var item = comboBox.Items.FindByValue(valuesToClone["Id"]);
item.Selected = true;
而且有效!但是,现在 Name
不再被克隆。它看起来像这样:
我不知道为什么,但是添加的代码有一个 side-effect 导致 NewValues
setter 方法失败。
底线:
底线相当简单:如何将 DevExpress 示例更改为也可以克隆引用类型属性的示例?
PS。我也 cross-posted my question on the DevExpress support forum.
您提到 "Qualification.Id"
不起作用,但您很可能在 EditItemTemplate
存在时尝试过。如果没有这样的模板,那么该代码实际上可以工作。
为了完整起见,将 fieldsToCopy
行代码更改为:
private string[] fieldsToCopy = { "Name", "Qualification.Id" };
并且确保没有EditItemTemplate
,然后就可以了。
或者,如果您出于某种原因无法使用 EditItemTemplate
,可以使用 "solution" 来确保该模板中的 ComboBox 绑定到克隆的值。确保使用以下代码挂接到 ComboBox 上的 OnDataBound
:
protected void qualificationCombo_DataBound(object sender, EventArgs e)
{
var column = grvPeople.Columns["Qualification"] as GridViewDataColumn;
var comboBox = grvPeople.FindEditRowCellTemplateControl(column, "qualificationCombo") as ASPxComboBox;
var item = comboBox.Items.FindByValue(valuesToClone["Id"]);
item.Selected = true;
}
这将正确地将 ComboBox 设置为克隆的值,同时还将 e.NewValues
用于普通字段的方法保持不变。