In XAF applications, view settings are stored for each user individually. When a user changes a view (for example, adds a column to a list view or groups a detail view's items), these settings are saved in the user's model differences and applied to this view the next time this view is displayed.
The built-in View Variants Module allows you to create multiple predefined view settings in the Model Editor or in code. It also allows an end user to select a view variant at runtime.
This example implements functionality required to save customized view settings as new view variants at runtime, share them between users, and allow any user who has appropriate permissions to select a variant and apply its settings to a view.
NOTE:
The approach demonstrated in this example may be inappropriate or overly complex in certain use cases. Thus, we cannot guarantee that it will work in all possible use case scenarios. Do not hesitate to modify it so it handles your business needs.
Implementation Details
The example application uses a persistent class to store view settings in the database and a view controller with actions used to manage these settings (create, apply, and delete). Each user can create his/her own view variants. Each view variant can be optionally marked as shared, so that other users can see this variant in the UI and apply it to their views.
Add a Persistent Class to Store View Settings
First, create the SettingsStore
business class used to store the View settings. This class should have the following properties:
Xml
- A string where serialized view settings are stored.Name
- The name of the view variant.OwnerId
- An identifier of the user who created this variant.IsShared
- Specifies whether this variant is shared with other users.ViewId
- An identifier of the view for which this variant is created.
Add a Custom View Controller
Create a ViewController
that defines the following behavior:
- The shared model settings are available to all users but cannot be edited by them.
- Each user has his/her own default settings saved in the user's model and used when no variant is used.
- The
SaveAsNewViewVariant
action creates a new view variant based on customizations made to a view. The created variant is assigned as the current variant. If this is the first variant created for the view, the action additionally creates a variant that stores the default settings (named "Default"). - The
SelectViewVariant
action allows a user to select a view variant from a combo box and makes the selected variant current. This action is available when at least one variant exists. When a user changes the current view variant, all customizations previously made to the view are lost, except for changes made to the "Default" view variant. - The
UpdateCurrentViewVariant
action saves customizations to the currently selected view variant. - The
DeleteViewVariant
action deletes the current view variant. After deletion, the "Default" view variant becomes current and its settings are applied. - The
UpdateDefaultViewVariant
action saves customizations made to the current view in the "Default" variant.
In the example application, the actions that ViewVariantsController
implements look as follows:
You can extend and adjust the demonstrated functionality based on your requirements. For example, you can:
- Use the Security System facilities to prohibit certain users from deleting view variants.
- Store the current variant in the model (see the Change the Application Model topic in our documentation) or in the user object's property and apply it when the corresponding view is opened.
Files to Review
Documentation
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.Persistent.BaseImpl;
using DevExpress.ExpressApp;
using System.ComponentModel;
using DevExpress.Persistent.BaseImpl.EF;
namespace ViewSettingsEF.Module.BusinessObjects {
public class SettingsStore : BaseObject {
[Browsable(false)]
public virtual string Xml { get; set; }
public virtual string Name { get; set; }
[Browsable(false)]
public virtual string OwnerId { get; set; }
public virtual Boolean IsShared { get; set; }
[Browsable(false)]
public virtual string ViewId { get; set; }
}
}
C#using System;
using System.Collections.Generic;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Utils;
using DevExpress.ExpressApp.Model;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp.Actions;
using DevExpress.ExpressApp.Templates;
namespace ViewSettingsEF.Module.BusinessObjects {
public class ViewVariantsController : ViewController {
private SimpleAction DeleteViewVariantAction;
private PopupWindowShowAction CreateViewVariantAction;
private SingleChoiceAction SelectViewVariantAction;
private SimpleAction UpdateCurrentViewVariantAction;
private SimpleAction UpdateDefaultSettingsWithSelectedVariantAction;
private string defaultUserSettings;
private Boolean isLayoutProcessed = false;
private Boolean isDefaultViewSelected = false;
private ChoiceActionItem lastSelectedItem = null;
private void SetDifferences(string xml, IModelView model) {
Dictionary<string, string> differences = new Dictionary<string, string>();
differences.Add("", xml);
UserDifferencesHelper.SetUserDifferences(model, differences);
}
private Boolean TryLoadViewVariantFromXML(string xml) {
Boolean result = false;
View savedView = Frame.View;
isLayoutProcessed = true;
foreach(ISupportUpdate controller in Frame.Controllers) {
controller.BeginUpdate();
}
try {
if(Frame.SetView(null, true, null, false)) {
if(isDefaultViewSelected) {
UpdateDefaultSettings(savedView.Model);
isDefaultViewSelected = false;
}
SetDifferences(xml, savedView.Model);
savedView.LoadModel(false);
Frame.SetView(savedView);
result = true;
}
}
finally {
foreach(ISupportUpdate controller in Frame.Controllers) {
controller.EndUpdate();
}
}
isLayoutProcessed = false;
return result;
}
private void SaveViewVariantToXML(SettingsStore store) {
isLayoutProcessed = true;
View.SaveModel();
isLayoutProcessed = false;
store.Xml = UserDifferencesHelper.GetUserDifferences(View.Model)[""];
((IObjectSpaceLink)store).ObjectSpace.CommitChanges();
}
private void UpdateDefaultSettings(IModelView model) {
defaultUserSettings = UserDifferencesHelper.GetUserDifferences(model)[""];
}
private void UpdateActions(string itemToSelectCaption) {
SelectViewVariantAction.Items.Clear();
lastSelectedItem = null;
CriteriaOperator criteria = CriteriaOperator.Parse("([ViewId] = ?) And ([IsShared] Or [OwnerId] is null Or [OwnerId] = ?)", View.Id, SecuritySystem.CurrentUserId.ToString());
IObjectSpace objectSpace = Application.CreateObjectSpace(typeof(SettingsStore));
var tst = objectSpace.GetObjects<SettingsStore>(criteria);
foreach (SettingsStore item in objectSpace.GetObjects<SettingsStore>(criteria)) {
SelectViewVariantAction.Items.Add(new ChoiceActionItem(item.Name, item));
}
if(SelectViewVariantAction.Items.Count > 0) {
ChoiceActionItem defaultItem = new ChoiceActionItem("Default", null);
SelectViewVariantAction.Items.Add(defaultItem);
ChoiceActionItem itemToSelect = SelectViewVariantAction.Items.FindItemByID(itemToSelectCaption);
SelectViewVariantAction.SelectedItem = (itemToSelect != null) ? itemToSelect : defaultItem;
lastSelectedItem = SelectViewVariantAction.SelectedItem;
}
UpdateActionsActive();
}
private void UpdateActionsActive() {
Boolean isActive = SelectViewVariantAction.Items.Count > 0 && SelectViewVariantAction.SelectedItem.Data != null;
DeleteViewVariantAction.Active["HasVariants"] = isActive;
UpdateCurrentViewVariantAction.Active["HasVariants"] = isActive;
UpdateDefaultSettingsWithSelectedVariantAction.Active["HasVariants"] = isActive;
}
private void DeleteViewVariantAction_Execute(object sender, SimpleActionExecuteEventArgs e) {
IObjectSpaceLink currentLayoutItem = SelectViewVariantAction.SelectedItem.Data as IObjectSpaceLink;
if(TryLoadViewVariantFromXML(defaultUserSettings)) {
IObjectSpace os = currentLayoutItem.ObjectSpace;
os.Delete(currentLayoutItem);
os.CommitChanges();
isDefaultViewSelected = true;
UpdateActions(null);
}
}
private void CreateViewVariantAction_CustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e) {
IObjectSpace objectSpace = e.Application.CreateObjectSpace(typeof(SettingsStore));
e.View = e.Application.CreateDetailView(objectSpace, objectSpace.CreateObject<SettingsStore>());
}
private void CreateViewVariantAction_Execute(object sender, PopupWindowShowActionExecuteEventArgs e) {
SettingsStore store = (SettingsStore)e.PopupWindowViewCurrentObject;
if(SecuritySystem.CurrentUserId != null) {
store.OwnerId = SecuritySystem.CurrentUserId.ToString();
}
store.ViewId = View.Id;
SaveViewVariantToXML(store);
string itemToSelectCaption = store.Name;
isDefaultViewSelected = false;
UpdateActions(itemToSelectCaption);
}
private void SelectViewVariantAction_Execute(object sender, SingleChoiceActionExecuteEventArgs e) {
bool isVariantChanged = false;
ChoiceActionItem currentItem = SelectViewVariantAction.SelectedItem;
if(currentItem.Data != null) {
if(TryLoadViewVariantFromXML(((SettingsStore)currentItem.Data).Xml)) {
isVariantChanged = true;
}
} else {
if(TryLoadViewVariantFromXML(defaultUserSettings)) {
isDefaultViewSelected = true;
isVariantChanged = true;
}
}
SelectViewVariantAction.SelectedItem = isVariantChanged ? currentItem : lastSelectedItem;
UpdateActionsActive();
}
private void UpdateCurrentViewVariantAction_Execute(object sender, SimpleActionExecuteEventArgs e) {
SaveViewVariantToXML(SelectViewVariantAction.SelectedItem.Data as SettingsStore);
}
private void UpdateDefaultSettingsWithSelectedVariantAction_Execute(object sender, SimpleActionExecuteEventArgs e) {
SaveViewVariantToXML(SelectViewVariantAction.SelectedItem.Data as SettingsStore);
UpdateDefaultSettings(View.Model);
}
private void View_ModelSaving(object sender, System.ComponentModel.CancelEventArgs e) {
if(!isLayoutProcessed && !isDefaultViewSelected) {
SetDifferences(defaultUserSettings, View.Model);
e.Cancel = true;
}
}
protected override void OnActivated() {
base.OnActivated();
View.ModelSaving += View_ModelSaving;
if(!isLayoutProcessed) {
UpdateDefaultSettings(View.Model);
isDefaultViewSelected = true;
UpdateActions(null);
}
}
protected override void OnDeactivated() {
View.ModelSaving -= View_ModelSaving;
base.OnDeactivated();
}
public ViewVariantsController() {
this.TargetViewNesting = Nesting.Root;
this.DeleteViewVariantAction = new SimpleAction(this, "DeleteViewVariant", "Edit");
this.DeleteViewVariantAction.Execute += new SimpleActionExecuteEventHandler(this.DeleteViewVariantAction_Execute);
this.CreateViewVariantAction = new PopupWindowShowAction(this, "SaveAsNewViewVariant", "Edit");
this.CreateViewVariantAction.CustomizePopupWindowParams += new CustomizePopupWindowParamsEventHandler(this.CreateViewVariantAction_CustomizePopupWindowParams);
this.CreateViewVariantAction.Execute += new PopupWindowShowActionExecuteEventHandler(this.CreateViewVariantAction_Execute);
this.SelectViewVariantAction = new SingleChoiceAction(this, "SelectViewVariant", "Edit");
this.SelectViewVariantAction.PaintStyle = ActionItemPaintStyle.Caption;
this.SelectViewVariantAction.Execute += new SingleChoiceActionExecuteEventHandler(this.SelectViewVariantAction_Execute);
this.UpdateCurrentViewVariantAction = new SimpleAction(this, "UpdateCurrentViewVariant", "Edit");
this.UpdateCurrentViewVariantAction.Execute += new SimpleActionExecuteEventHandler(this.UpdateCurrentViewVariantAction_Execute);
this.UpdateDefaultSettingsWithSelectedVariantAction = new SimpleAction(this, "UpdateDefaultViewVariant", "Edit");
UpdateDefaultSettingsWithSelectedVariantAction.Execute += UpdateDefaultSettingsWithSelectedVariantAction_Execute;
this.Actions.Add(this.DeleteViewVariantAction);
this.Actions.Add(this.CreateViewVariantAction);
this.Actions.Add(this.SelectViewVariantAction);
this.Actions.Add(this.UpdateCurrentViewVariantAction);
this.Actions.Add(this.UpdateDefaultSettingsWithSelectedVariantAction);
}
}
}