matyas.boros-gmail
-
9/1/2009 5:18:15 AM
RE:Gridview Viewstate in custom webpart not working
Hi,
yes i got the reply from Helena, and she suggested the above code. Obviously it worked, but in some cases i bound the gridview to object lists, that are not serializable. In this case i would need to make it serializable first, and thensave it to the viewstate. This in a case of a usercontrol with multiple gridviews might be a lot of work, or if you diddnt write the original usercontrol, even too much. The best workaround i found was to load the usercontrol dynamically from another one, as it is done in the general webpart (usercontrol.ascx). That one lacks the properties, but the code can be simply modified for this purpose. I used the below code:
In app_code: WrapperBase.cs
using System; using System.Web.UI;
using CMS.PortalControls; using CMS.GlobalHelper; using System.Collections.Generic; using System.Reflection; using System.Web.UI.WebControls;
public abstract class WrapperBase : CMSAbstractWebPart {
// key is the public UC property name, value is the CMS property name protected virtual Dictionary<string, string> StringProperties { get { return new Dictionary<string, string>(); } }
// key is the public UC property name, value is the CMS property name protected virtual Dictionary<string, string> BoolProperties { get { return new Dictionary<string, string>(); } }
protected abstract string UserControlPath { get; }
protected abstract Label _lblError { get; }
/// <summary> /// Content loaded event handler /// </summary> public override void OnContentLoaded() { base.OnContentLoaded(); SetupControl(); }
/// <summary> /// Initializes the control properties /// </summary> protected void SetupControl() { if (this.StopProcessing) { // Do not process } else { } }
/// <summary> /// Loads the user control /// </summary> protected void LoadControl() { if (!string.IsNullOrEmpty(UserControlPath)) { try { Control ctrl = Page.LoadControl(UserControlPath); ctrl.ID = "userControlElem"; Controls.Add(ctrl); string temp = ""; foreach (string key in StringProperties.Keys) { PropertyInfo pi = ctrl.GetType().GetProperty(key, BindingFlags.Instance | BindingFlags.Public); if (pi != null) pi.SetValue(ctrl, ValidationHelper.GetString(this.GetValue(StringProperties[key]), temp), null); } foreach (string key in BoolProperties.Keys) { PropertyInfo pi = ctrl.GetType().GetProperty(key, BindingFlags.Instance | BindingFlags.Public); if (pi != null && PartInstance != null) pi.SetValue(ctrl, Boolean.Parse((string)PartInstance.GetValue(BoolProperties[key])), null); }
} catch (Exception ex) { _lblError.Text = "[" + this.ID + "] " + ResHelper.GetString("WebPartUserControl.ErrorLoad") + ": " + ex.Message; _lblError.ToolTip = ex.StackTrace; _lblError.Visible = true; } } }
protected override void OnInit(EventArgs e) { base.OnInit(e);
// The control must load after OnInit to properly load its viewstate LoadControl(); } }
This is the modification of the Usercontrol.ascx.cs file, that automatically sets the CMS properties to public usercontrol properties. I only used bool and string but you can easily add other ones if you need.
Then the code looks really simple:
testcontrol.ascx:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="~/CMSWebParts/Wrappers/testcontrol.ascx.cs" Inherits="CMSWebParts_Wrapper_testcontrol" %> <asp:Label ID="lblError" runat="server" EnableViewState="false" Visible="false" />
and testcontrol.ascx.cs
using System; using System.Web.UI;
using CMS.PortalControls; using CMS.GlobalHelper; using System.Collections.Generic; using System.Web.UI.WebControls;
public partial class CMSWebParts_Wrapper_testcontrol : WrapperBase { protected override Dictionary<string, string> StringProperties { get { return new Dictionary<string, string> { {"publicUCProperty", "CMSProperty"} }; } }
protected override Dictionary<string, string> BoolProperties { get { return new Dictionary<string, string> { {"publicUCBoolProperty", "CMSBoolPropertyName"} }; } }
protected override string UserControlPath { get { return "~/CMSWebParts/originalcontrol/testcontrol.ascx"; } }
protected override Label _lblError { get { return lblError; } } }
This basically allows you to use any usercontrol without even changing the baseclass. I found it the least work, as you only have to change the usercontrolpath, and the property names for each control. I wish they would work by default though, so i could save even this work. Let me know if you have an easier solution.
|