I'm trying to follow the DevExpress documentation example on cloning rows. The basics are easy to get right, but things get tricky when you try to clone properties other than value types.
First attempt / setting up a repro:
I've narrowed my real scenario to a small(ish) repro of the problem. The following is all part of a freshly created ASP.NET 2.0 webforms application. First, suppose these domain objects (that'll double as DTO's here too):
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; }
}
Then there are two quick 'n dirty data source classes like so:
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]
}
};
}
}
The default.aspx page will first register dx to DevExpress namespaces:
<%# 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" %>
And have a single form with this code in it:
<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>
The code behind contains the code to clone a row into a fresh edit form, based on aforementioned DevExpress example, like so:
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];
}
}
This works for the Name property, but not so much for the Qualification property. It shows like this on the page:
I've also tried "Qualification.Id" and "Qualification" as field names to copy, but no dice. At any rate, I'm pretty sure it should be "Id" as in my example though, because the debugger shows the correct GetRowValues return value only for that case.
Second attempt / custom code to handle the dropdown:
So I'm thinking I need to have some custom code to set the NewValue for a dropdown. First I create an EditItemTemplate for the Qualification column like so:
<EditItemTemplate>
<dx:ASPxComboBox
runat="server"
ID="qualificationCombo"
DataSourceID="qualificationsDataSource"
TextField="Title"
ValueField="Id"
ValueType="System.Int64" />
</EditItemTemplate>
And then I add this code to 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;
And it works! However, now the Name is no longer cloned. It looks like this:
I have no clue why, but the added code has a side-effect causing the NewValues setter approach to fail.
Bottom Line:
The bottom line is rather simple: how do I change the DevExpress example into one that can also clone reference type properties?
PS. I've also cross-posted my question on the DevExpress support forum.
You mention that "Qualification.Id" doesn't work, but you most likely tried that while the EditItemTemplate was there. If there is no such template then that code actually works.
To be complete, change the fieldsToCopy line of code to:
private string[] fieldsToCopy = { "Name", "Qualification.Id" };
And make sure there's no EditItemTemplate, then it'll work.
Alternatively, if you are stuck with a EditItemTemplate for some reason, there's one "solution" to make sure the ComboBox in that template gets bound to the cloned value. Make sure you hook into OnDataBound on the ComboBox with the following code:
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;
}
This will properly set the ComboBox to the cloned value, while also leaving the e.NewValues approach for plain fields intact.
Related
How to select Rows on GridPanel using ext.net Library on ASP.NET.
When i put this code on Page_Load event, it's work fine :
protected void Page_Load(object sender, EventArgs e)
{
RowSelectionModel sm = gridRolesPermission.GetSelectionModel() as RowSelectionModel;
sm.SelectedRows.Add(new SelectedRow(1));
sm.SelectedRows.Add(new SelectedRow(2));
}
but when i would to select CheckBoxs on Ajax event, it's not working !
[DirectMethod]
public void FillPermissionForSelectedRole()
{
RowSelectionModel sm = gridRolesPermission.GetSelectionModel() as RowSelectionModel;
sm.SelectedRows.Add(new SelectedRow(1));
sm.SelectedRows.Add(new SelectedRow(2));
}
On view :
....
<Listeners>
<Command Handler="App.direct.FillPermissionForSelectedRole();" />
</Listeners>
...
Any Help Please !
In your example,when u click the button(directMethod button),a pamatercollection sent to the server called CheckboxSelectionModel1 .on server side, u can get the this parameter collection like this.
string hh= HttpContext.Current.Request["CheckboxSelectionModel1"];
*CheckboxSelectionModel1 is the model name of the grid on your example.
in your case like that
[DirectMethod]
public void FillPermissionForSelectedRole()
{
string hh= HttpContext.Current.Request["CheckboxSelectionModel1"];
}
string hh should be something like this depents on the what u checked on grid.
"[{"RecordID":5,"RowIndex":5},{"RecordID":7,"RowIndex":7},{"RecordID":3,"RowIndex":3}]"
later u can desrialize this string and get the RecordID something like this
var rw = JSON.Deserialize<Row[]>(hh);
string txt = "";
foreach (var item in rw)
{
txt += item.RecordID;
}
and the row class
public class Row{
public string RecordID { get; set; }
public string RowIndex { get; set; }
}
to resolve this probleme i should add this line to upadate modifications :
sm.UpdateSelection();
This is the HTML. I have a repeater that contains a user control.
<asp:Repeater ID="rpNewHire" runat="server">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<user:CKListByDeprtment ID = "ucCheckList"
DepartmentID= '<%# Eval("DepID")%>'
BlockTitle = '<%# Eval("DepName")%>'
runat = "server"></user:CKListByDeprtment>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
DepartmentID is a property that I defined inside the user control.
int departmentID;
public int DepartmentID
{
get { return departmentID; }
set { departmentID = value; }
}
And this is how I am trying to access it
protected void Page_Load(object sender, EventArgs e)
{
int test = departmentID;
}
When the page loads for the first time, departmentID has a value. However, when the page Posts back, that value is always 0.
All variables (and controls) are disposed at the end of the page's lifecycle. So you need a way to persist your variable, e.g. in the ViewState.
public int DepartmentID
{
get {
if (ViewState["departmentID"] == null)
return int.MinValue;
else
return (int)ViewState["departmentID"];
}
set { ViewState["departmentID"] = value; }
}
The MSDN Magazine article "Nine Options for Managing Persistent User State in Your ASP.NET Application" is useful, but it's no longer viewable on the MSDN website. It's in the April 2003 edition, which you can download as a Windows Help file (.chm). (Don't forget to bring up the properties and unblock the "this was downloaded from the internet" thing, otherwise you can't view the articles.)
Change your property to use viewstate
int departmentID = 0;
public int DepartmentID
{
get {
if(ViewState["departmentID"]!=null)
{ departmentID = Int32.Parse(ViewState["departmentID"]); };
return departmentID;
}
set { ViewState["departmentID"] = value; }
}
I have a simple test application which reproduces an error I encountered recently. Basically I have a simple WinForm with databound TextBox and DateTimePicker controls, and a button. When I execute the code below (on the button click), I get the error "DataBinding cannot find a row in the list that is suitable for all bindings". If I move the DataSource assignment into the form's constructor, I don't get the error.
If I remove the data binding for the DateTimePicker, it works fine.
Can anyone explain what the problem is ?
public partial class Form1 : Form
{
private BindingSource bs;
public Form1()
{
InitializeComponent();
button1.Click += new EventHandler(button1_Click);
bs = new BindingSource();
bs.DataSource = typeof(Thing);
this.textBox1.DataBindings.Add("Text", bs, "MyString");
this.dateTimePicker1.DataBindings.Add(new Binding("Value", bs, "MyDate"));
//Thing thing = new Thing { MyString = "Hello", MyNumber = 123, MyDate = DateTime.Parse("01-Jan-1970") };
//bs.DataSource = thing;
}
private void button1_Click(object sender, EventArgs e)
{
Thing thing = new Thing { MyString = "Hello", MyNumber = 123, MyDate = DateTime.Parse("01-Jan-1970") };
bs.DataSource = thing;
}
}
public partial class Thing
{
public String MyString { get; set; }
public Int32 MyNumber { get; set; }
public DateTime MyDate { get; set; }
}
}
Thanks
Edit:
It seems that if I change the data binding for the DateTimePicker control such that I bind to the "Text" property, the problem goes away. I don't understand why that would be though, because "Value" is valid for data binding.
How to bind property in Two Way?
Here is my Code:
public interface IDataOperations
{
string GetData();
string SaveData();
}//close interface
public class Vendor : IDataOperations
{
private string _vendorName = "My Vendor Name";
public string VendorName
{
get { return _vendorName; }
set { _vendorName = value; }
}
}
How can I bind VendorName in my Xaml? I need to bind to Text Box in such a way that if user changes text box value, it should also change the value of that VendorObject too.
Where should I declare VendorObject? Either in xaml.cs file or xaml by using ?
your XAML code should look like
<TextBox Binding="{VendorName}" Name="textBox1" />
and on your Window_Loaded function add this code:
textBox1.DataContext=v;
where v is an instance of the Vendor class.
I'm working on making a modification to a site built with ASP/C#, and one of the tasks was to add in the display of 2 RSS feeds - one from the site's internal blog, and the other from the site's Twitter account. However, I seem to continually get empty feeds from both, even though I've confirmed that I'm pointing to the correct URL of the feeds. My code is shown below.
private void GetTwitterRSS()
{
IEnumerable items = Cache["TwitterFeed"] as List<SyndicationItem>;
if (items == null)
{
try
{
SyndicationFeed blogFeed = SyndicationFeed.Load(XmlReader.Create("http://twitter.com/statuses/user_timeline/84668697.rss"));
items = blogFeed.Items;
}
catch
{
items = new List<SyndicationItem>();
}
Cache.Insert("TwitterFeed", items, null, DateTime.Now.AddMinutes(5.0),TimeSpan.Zero);
twitterrssRepeater.DataSource = items;
twitterrssRepeater.DataBind();
}
}
private void GetBlogRSS()
{
IEnumerable items = Cache["BlogFeed"] as List<SyndicationItem>;
if (items == null)
{
try
{
SyndicationFeed blogFeed = SyndicationFeed.Load(XmlReader.Create("http://www.rentseeker.ca/blog/?feed=rss2"));
items = blogFeed.Items;
}
catch
{
items = new List<SyndicationItem>();
}
Cache.Insert("BlogFeed", items, null, DateTime.Now.AddHours(1.0),TimeSpan.Zero);
blogrssRepeater.DataSource = items;
blogrssRepeater.DataBind();
}
}
protected string DisplayBlogFeedItem(SyndicationItem item)
{
return string.Format(#"<p>{1}</p><p><strong>{2}</strong></p><p>{3}</p>",
FormatPublishDate(item.PublishDate.DateTime),
item.Title.Text,
item.Summary.Text);
}
protected string DisplayTwitterFeedItem(SyndicationItem item)
{
return string.Format(#"<li>{1}</li>",
item.Title.Text);
}
The code on the page is:
<ul>
<asp:ListView ID="twitterrssRepeater" runat="server">
<ItemTemplate>
<%# DisplayTwitterFeedItem((Container as ListViewDataItem).DataItem as System.ServiceModel.Syndication.SyndicationItem) %>
</ItemTemplate>
</asp:ListView>
</ul>
and
<asp:ListView ID="blogrssRepeater" runat="server">
<ItemTemplate>
<%# DisplayBlogFeedItem((Container as ListViewDataItem).DataItem as System.ServiceModel.Syndication.SyndicationItem) %>
</ItemTemplate>
</asp:ListView>
Clearly, I'm missing something. From what I've read, I understand that I'm supposed to authenticate myself in order to view a Twitter feed - I have the credentials, but am not sure how to pass them into SyndicationFeed when I load it.
Any tips, suggestions, or direction for further information is greatly appreciated.
Here's a simple example I would use to receive my Twitter feed (I'm only getting name, update title & id)
public class TwitterFeed
{
public string Name { get; set; }
public string Title { get; set; }
public string Id { get; set; }
}
Then the method to get the feed
public List<TwitterFeed> GetTwitterFeed(string name)
{
List<TwitterFeed> list = new List<TwitterFeed>();
XmlReader reader = XmlReader.Create(string.Format("http://search.twitter.com/search.atom?q=to:{0}", name));
SyndicationFeed feed = SyndicationFeed.Load(reader);
var tweetItems = from item in feed.Items
select new TwitterFeed()
{
Name = item.Authors.First().Name,
Title = item.Title.Text,
Id = item.Id
};
return tweetItems.ToList();
}
Hope that helps
SyndicationFeed.Items is not a List, but implements IEnumerable interface, so instead of
IEnumerable items = Cache["BlogFeed"] as List<SyndicationItem>;
use the following line:
IEnumerable items = Cache["BlogFeed"] as IEnumerable<SyndicationItem>;