Using custom objects in Widgets framework
When working with Widgets framework in upcoming BlogEngine 1.4, you have three choices for saving widget settings to data store: StringDictionary, XmlDocument and CustomObject. StringDictionary is really a simple one and will fit your needs in a lot (if not most) cases. XmlDocument provides more flexible data storage excellent for complex hierarchical data structures, but it might be a daunting task to handle. You might look at LinkList that comes with standard install on example of using XmlDocument. Custom object provides you with familiar way of working with complex data, but it has it's own gotchas. I'll try to address some of them here.
- Your custom object must inherit from CustomObjectBase and use Serializable() attribute.
[Serializable()]
public class CustomSettings : CustomObjectBase {}
- Object must have public default constructor with no parameters for serialization to work.
- All public properties must support ISerializable interface. Most common objects in .Net framework do, but for some you'll need to implement your own interface to use them.
- Public properties must have getters and setters - read only will not be serialized.
- You can mark public property with [XmlIgnore] if you don't want it be serialized.
- To get widget settings from data store use:
CustomSettings cs = new CustomSettings();
cs = (CustomSettings)GetSettings(ObjectType.CustomObject, new CustomSettings());
- To save settings to data store:
CustomSettings settings = new CustomSettings();
settings.TheString = txtString.Text;
settings.TheInteger = int.Parse(txtInteger.Text);
// more...
SaveSettings(settings);
- You can't use some of the controls (drop downs, grid views etc.) on widgets form directly. There are issues with rendering nested controls in asp.net and you'll get rendering errors trying to put them on the form. The work around is to use placeholder and inject controls dynamically on form load:
if (cs.TheTable != null && cs.TheTable.Rows.Count > 0)
{
GridView gv = new GridView();
gv.DataSource = cs.TheTable;
gv.DataBind();
PlaceHolder2.Controls.Add(gv);
}
It well might be a better way of doing it, but I haven't found it. I also used Initialized property for custom object to see if it has been saved yet. If it wasn't, controls are not loaded for the same reason - they will error out.
Example of simple but probably typical custom object you can see below. I've added it to the edit control so I don't have to create it's own class that has to be dropped to App_Code. It makes it easier to distribute widget, but if you prefer you can certainly create stand alone class.
[Serializable()]
public class CustomSettings : CustomObjectBase
{
public CustomSettings() { }
private string _str;
private int _int;
private bool _bool;
private string[] _array;
private DataTable _table;
private bool _init;
public string TheString { get { return _str; } set { _str = value; } }
public int TheInteger { get { return _int; } set { _int = value; } }
public bool TheBool { get { return _bool; } set { _bool = value; } }
public string[] TheArray { get { return _array; } set { _array = value; } }
public DataTable TheTable { get { return _table; } set { _table = value; } }
public bool Initialized { get { return _init; } set { _init = value; } }
}
Attached is a sample widget (CustomSample) that I put together just to demonstrate how you can use most common data types in custom object to play well with your widget. It does not do lot, but you can get ideas how you can use this technics with your own widgets that hopefully will be a whole lot more useful :)
For change set 10610 and up. Unzip to "~/widgets" folder: customsample.zip