This module contains a collection of common features frequently used in most applications. Most features are disabled by default and can be enabled through the Model.xafml files.
This module contains a collection of common features frequently used in most applications. Most features are disabled by default and can be enabled through the Model.xafml files.
Install-Package 'Llamachant.ExpressApp.Module'
public MyModule() {
RequiredModuleTypes.Add(typeof(LlamachantFrameworkModule));
}
OR
services.AddXaf(Configuration, builder => {
builder.UseApplication<ExpressAppBlazorApplication>();
builder.Modules.AddLlamachantFrameworkModule(); //Add this line
});
Some features listed in the agnostic module require the platform specific module to be registered in your application. Repeat the instructions above for the platform specific modules in the platform specific projects.
Install-Package 'Llamachant.ExpressApp.Module'
public MyModule() {
RequiredModuleTypes.Add(typeof(LlamachantFrameworkModule));
}
OR
services.AddXaf(Configuration, builder => {
builder.UseApplication<ExpressAppBlazorApplication>();
builder.Modules.AddLlamachantFrameworkModule(); //Add this line
});
Some features listed in the agnostic module require the platform specific module to be registered in your application. Repeat the instructions above for the platform specific modules in the platform specific projects.
A message can be shown when an action is finished executing (The ExecuteCompleted event is called).
| Application | Llamachant Framework | Values |
|---|---|---|
| ExecuteCompletedMessage | String | |
| ExecuteCompletedMessageInformationType | String | |
| ExecuteCompletedMessageWinMesageType | String | |
| ExecuteCompletedMessageDuration | String |
A message can be shown when an action is finished executing (The ExecuteCompleted event is called).
| Application | Llamachant Framework | Values |
|---|---|---|
| ExecuteCompletedMessage | String | |
| ExecuteCompletedMessageInformationType | String | |
| ExecuteCompletedMessageWinMesageType | String | |
| ExecuteCompletedMessageDuration | String |
By default, views representing many to many collections show a New and Delete action as well as the Link and Unlink actions. The Link and Unlink actions allow you to select existing items from a pool of existing records where as the New and Delete actions bypass this lookup. Setting this model option allows you to prevent the user from deleting records from the list view.
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowDeleteNonAggregatedObjects | True / False | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | AllowDeleteNonAggregatedObjects | True / False |
By default, views representing many to many collections show a New and Delete action as well as the Link and Unlink actions. The Link and Unlink actions allow you to select existing items from a pool of existing records where as the New and Delete actions bypass this lookup. Setting this model option allows you to prevent the user from deleting records from the list view.
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowDeleteNonAggregatedObjects | True / False | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | AllowDeleteNonAggregatedObjects | True / False |
This model option allows you to prevent a List View from opening its corresponding Detail View when a record is clicked.
| Application | Llamachant Framework | Values |
|---|---|---|
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | AllowOpenDetailView | True / False |
This model option allows you to prevent a List View from opening its corresponding Detail View when a record is clicked.
| Application | Llamachant Framework | Values |
|---|---|---|
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | AllowOpenDetailView | True / False |
Enable options on tabbed layout groups to bold the caption and/or show the number of records within the nested collection within each tabbed group. These options make it easy to determine which data is populated within the current record.
This feature requires a platform specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| BoldTabsWithCounts | True / False | |
| ShowCountsInTabs | True / False | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_DetailView | ||
| Layout | ||
| Items | ||
| TabbedLayoutItem | AllowHighlightBold | True / False |
| AllowHighlightCounts | True / False |
Enable options on tabbed layout groups to bold the caption and/or show the number of records within the nested collection within each tabbed group. These options make it easy to determine which data is populated within the current record.
This feature requires a platform specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| BoldTabsWithCounts | True / False | |
| ShowCountsInTabs | True / False | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_DetailView | ||
| Layout | ||
| Items | ||
| TabbedLayoutItem | AllowHighlightBold | True / False |
| AllowHighlightCounts | True / False |
Hide the toolbar on a List View or allow the user to toggle the toolbar's visibility.
The AllowToolbarVisibilityToggle is only supported in WinForms
| Application | Llamachant Framework | Values |
|---|---|---|
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | ToolbarVisible | True / False |
| AllowToolbarVisibilityToggle | True / False |
Hide the toolbar on a List View or allow the user to toggle the toolbar's visibility.
The AllowToolbarVisibilityToggle is only supported in WinForms
| Application | Llamachant Framework | Values |
|---|---|---|
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | ToolbarVisible | True / False |
| AllowToolbarVisibilityToggle | True / False |
Enable this features when you want list views to automatically use the last used search text when returning to the view.
This feature does not apply to lookup controls or lookup windows
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowPreservingFullTextSearch | True / False | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | PreserveFullTextSearch | True / False |
Enable this features when you want list views to automatically use the last used search text when returning to the view.
This feature does not apply to lookup controls or lookup windows
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowPreservingFullTextSearch | True / False | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | PreserveFullTextSearch | True / False |
Upload files to destinations outside of the database by implementing the IFileAttachment interface.
namespace LlamachantFramework.Module.Interfaces;
public interface IFileAttachment : IFileData
{
new int Size { get; set; }
string StorageLocation { get; set; }
string CalculateStorageLocation();
}
using LlamachantFramework.FileAttachments.AzureBlobStorage;
using LlamachantFramework.Module.Interfaces;
public class Document(Session session) : BaseObject(session), IFileAttachment
{
private Client _Client;
[Association]
public Client Client
{
get { return _Client; }
set { SetPropertyValue<Client>(nameof(Client), ref _Client, value); }
}
private string _StorageLocation;
[Size(1024)]
public string StorageLocation
{
get { return _StorageLocation; }
set { SetPropertyValue<string>(nameof(StorageLocation), ref _StorageLocation, value); }
}
public string CalculateStorageLocation() => $@"Client Files\{DateTime.Today.Year}\";
#region IFileData
private string _FileName;
public string FileName
{
get { return _FileName; }
set { SetPropertyValue<string>(nameof(FileName), ref _FileName, value); }
}
private int _Size;
public int Size
{
get { return _Size; }
set { SetPropertyValue<int>(nameof(Size), ref _Size, value); }
}
public void LoadFromStream(string filename, Stream stream)
{
GetStorageProcessor().LoadFromStream(filename, stream, this);
}
public void SaveToStream(Stream stream)
{
GetStorageProcessor().SaveToStream(stream, this);
}
public void Clear()
{
GetStorageProcessor().Clear(this);
}
#endregion
private AzureBlobStorageFileAttachmentProcessor GetStorageProcessor() => new AzureBlobStorageFileAttachmentProcessor("<your azure blob storage connection string>", "<your azure container name>");
}
To simplify attachment processing, the Llamachant.ExpressApp.Module package includes a FileAttachmentProcessorBase class that you can inherit from to create your own storage processors. For common scenarios, there is a built in FileStorageFileAttachmentProcessor that can be used to save files to the local file system, or you can include the Llamachant.ExpressApp.FileAttachments.AzureBlobStorage package to utilize the AzureBlobStorageFileAttachmentProcessor as shown in the example above.
using LlamachantFramework.Module.Interfaces;
public class FileStorageFileAttachmentProcessor : FileAttachmentProcessorBase
{
public bool DeleteOnClear { get; set; } = true;
public bool OverwriteExistingFiles { get; set; } = false;
public override void Clear(IFileAttachment attachment)
{
if (DeleteOnClear)
DeleteFromStorage(attachment);
attachment.FileName = null;
attachment.StorageLocation = null;
attachment.Size = 0;
}
public override void DeleteFromStorage(IFileAttachment attachment)
{
if (!String.IsNullOrEmpty(attachment?.StorageLocation) && File.Exists(attachment.StorageLocation))
File.Delete(attachment.StorageLocation);
}
public override void LoadFromStream(string fileName, Stream stream, IFileAttachment attachment)
{
string path = attachment.CalculateStorageLocation();
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
path = Path.Combine(path, fileName);
int i = 2;
while (!OverwriteExistingFiles && File.Exists(path))
{
string folder = Path.GetDirectoryName(path);
string filename = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path);
path = Path.Combine(folder, $"{filename} ({i}){extension}");
i++;
}
using (FileStream fs = new FileStream(path, OverwriteExistingFiles ? FileMode.Create : FileMode.CreateNew, FileAccess.Write))
{
stream.CopyTo(fs);
}
attachment.StorageLocation = path;
attachment.Size = Convert.ToInt32(stream.Length);
attachment.FileName = fileName;
}
public override void SaveToStream(Stream stream, IFileAttachment attachment)
{
if (!String.IsNullOrEmpty(attachment?.StorageLocation) && File.Exists(attachment.StorageLocation))
{
using (FileStream fs = File.OpenRead(attachment.StorageLocation))
{
fs.CopyTo(stream);
}
}
}
}
Upload files to destinations outside of the database by implementing the IFileAttachment interface.
namespace LlamachantFramework.Module.Interfaces;
public interface IFileAttachment : IFileData
{
new int Size { get; set; }
string StorageLocation { get; set; }
string CalculateStorageLocation();
}
using LlamachantFramework.FileAttachments.AzureBlobStorage;
using LlamachantFramework.Module.Interfaces;
public class Document(Session session) : BaseObject(session), IFileAttachment
{
private Client _Client;
[Association]
public Client Client
{
get { return _Client; }
set { SetPropertyValue<Client>(nameof(Client), ref _Client, value); }
}
private string _StorageLocation;
[Size(1024)]
public string StorageLocation
{
get { return _StorageLocation; }
set { SetPropertyValue<string>(nameof(StorageLocation), ref _StorageLocation, value); }
}
public string CalculateStorageLocation() => $@"Client Files\{DateTime.Today.Year}\";
#region IFileData
private string _FileName;
public string FileName
{
get { return _FileName; }
set { SetPropertyValue<string>(nameof(FileName), ref _FileName, value); }
}
private int _Size;
public int Size
{
get { return _Size; }
set { SetPropertyValue<int>(nameof(Size), ref _Size, value); }
}
public void LoadFromStream(string filename, Stream stream)
{
GetStorageProcessor().LoadFromStream(filename, stream, this);
}
public void SaveToStream(Stream stream)
{
GetStorageProcessor().SaveToStream(stream, this);
}
public void Clear()
{
GetStorageProcessor().Clear(this);
}
#endregion
private AzureBlobStorageFileAttachmentProcessor GetStorageProcessor() => new AzureBlobStorageFileAttachmentProcessor("<your azure blob storage connection string>", "<your azure container name>");
}
To simplify attachment processing, the Llamachant.ExpressApp.Module package includes a FileAttachmentProcessorBase class that you can inherit from to create your own storage processors. For common scenarios, there is a built in FileStorageFileAttachmentProcessor that can be used to save files to the local file system, or you can include the Llamachant.ExpressApp.FileAttachments.AzureBlobStorage package to utilize the AzureBlobStorageFileAttachmentProcessor as shown in the example above.
using LlamachantFramework.Module.Interfaces;
public class FileStorageFileAttachmentProcessor : FileAttachmentProcessorBase
{
public bool DeleteOnClear { get; set; } = true;
public bool OverwriteExistingFiles { get; set; } = false;
public override void Clear(IFileAttachment attachment)
{
if (DeleteOnClear)
DeleteFromStorage(attachment);
attachment.FileName = null;
attachment.StorageLocation = null;
attachment.Size = 0;
}
public override void DeleteFromStorage(IFileAttachment attachment)
{
if (!String.IsNullOrEmpty(attachment?.StorageLocation) && File.Exists(attachment.StorageLocation))
File.Delete(attachment.StorageLocation);
}
public override void LoadFromStream(string fileName, Stream stream, IFileAttachment attachment)
{
string path = attachment.CalculateStorageLocation();
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
path = Path.Combine(path, fileName);
int i = 2;
while (!OverwriteExistingFiles && File.Exists(path))
{
string folder = Path.GetDirectoryName(path);
string filename = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path);
path = Path.Combine(folder, $"{filename} ({i}){extension}");
i++;
}
using (FileStream fs = new FileStream(path, OverwriteExistingFiles ? FileMode.Create : FileMode.CreateNew, FileAccess.Write))
{
stream.CopyTo(fs);
}
attachment.StorageLocation = path;
attachment.Size = Convert.ToInt32(stream.Length);
attachment.FileName = fileName;
}
public override void SaveToStream(Stream stream, IFileAttachment attachment)
{
if (!String.IsNullOrEmpty(attachment?.StorageLocation) && File.Exists(attachment.StorageLocation))
{
using (FileStream fs = File.OpenRead(attachment.StorageLocation))
{
fs.CopyTo(stream);
}
}
}
}
While the built-in Audit Trail Module from DevExpress is powerful, users often benefit from a quick and accessible view of when an object was created, modified, or deleted. The ITrackedObject interface simplifies this process by enabling lightweight audit tracking across your business objects. By implementing the ITrackedObject interface, you can leverage the TrackedObjectHelper utility class to remove repetitive code.
When possible, consider creating a CustomBaseObject that your persistent classes inherit from. This base class can utilize the TrackedObjectHelper to automatically manage timestamps and user tracking - minimizing boilerplate and ensuring consistency across your models.
using DevExpress.Data.Filtering;
using LlamachantFramework.Module.Interfaces;
using LlamachantFramework.Module.Utils;
[NonPersistent]
public abstract class CustomBaseObject : BaseObject , ITrackedObject
{
public CustomBaseObject(Session session) : base(session) { }
public override void AfterConstruction()
{
base.AfterConstruction();
TrackedObjectHelper.AfterConstruction(this, nameof(CreatedBy));
}
protected override void OnSaving()
{
TrackedObjectHelper.OnSaving(this, nameof(LastModifiedBy));
base.OnSaving();
}
protected override void OnDeleting()
{
TrackedObjectHelper.OnDeleting(this, nameof(DeletedBy));
base.OnDeleting();
}
//If you don't use security in your application, this can return null
public object GetCurrentUser() => Session.FindObject<PermissionPolicyUser>(CriteriaOperator.Parse("[Oid] = CurrentUserId()"));
private DateTime _CreatedOn;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("DisplayFormat", "{0:g}")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
public DateTime CreatedOn
{
get { return _CreatedOn; }
set { SetPropertyValue<DateTime>(nameof(CreatedOn), ref _CreatedOn, value); }
}
private DateTime _ModifiedOn;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("DisplayFormat", "{0:g}")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
public DateTime ModifiedOn
{
get { return _ModifiedOn; }
set { SetPropertyValue<DateTime>(nameof(ModifiedOn), ref _ModifiedOn, value); }
}
private DateTime _DeletedOn;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("DisplayFormat", "{0:g}")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
public DateTime DeletedOn
{
get { return _DeletedOn; }
set { SetPropertyValue<DateTime>(nameof(DeletedOn), ref _DeletedOn, value); }
}
private PermissionPolicyUser _CreatedBy;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
[SearchMemberOptions(SearchMemberMode.Exclude)]
public PermissionPolicyUser CreatedBy
{
get { return _CreatedBy; }
set { SetPropertyValue<PermissionPolicyUser>(nameof(CreatedBy), ref _CreatedBy, value); }
}
private PermissionPolicyUser _LastModifiedBy;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
[SearchMemberOptions(SearchMemberMode.Exclude)]
public PermissionPolicyUser LastModifiedBy
{
get { return _LastModifiedBy; }
set { SetPropertyValue<PermissionPolicyUser>(nameof(LastModifiedBy), ref _LastModifiedBy, value); }
}
private PermissionPolicyUser _DeletedBy;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
[SearchMemberOptions(SearchMemberMode.Exclude)]
public PermissionPolicyUser DeletedBy
{
get { return _DeletedBy; }
set { SetPropertyValue<PermissionPolicyUser>(nameof(DeletedBy), ref _DeletedBy, value); }
}
}
While the built-in Audit Trail Module from DevExpress is powerful, users often benefit from a quick and accessible view of when an object was created, modified, or deleted. The ITrackedObject interface simplifies this process by enabling lightweight audit tracking across your business objects. By implementing the ITrackedObject interface, you can leverage the TrackedObjectHelper utility class to remove repetitive code.
When possible, consider creating a CustomBaseObject that your persistent classes inherit from. This base class can utilize the TrackedObjectHelper to automatically manage timestamps and user tracking - minimizing boilerplate and ensuring consistency across your models.
using DevExpress.Data.Filtering;
using LlamachantFramework.Module.Interfaces;
using LlamachantFramework.Module.Utils;
[NonPersistent]
public abstract class CustomBaseObject : BaseObject , ITrackedObject
{
public CustomBaseObject(Session session) : base(session) { }
public override void AfterConstruction()
{
base.AfterConstruction();
TrackedObjectHelper.AfterConstruction(this, nameof(CreatedBy));
}
protected override void OnSaving()
{
TrackedObjectHelper.OnSaving(this, nameof(LastModifiedBy));
base.OnSaving();
}
protected override void OnDeleting()
{
TrackedObjectHelper.OnDeleting(this, nameof(DeletedBy));
base.OnDeleting();
}
//If you don't use security in your application, this can return null
public object GetCurrentUser() => Session.FindObject<PermissionPolicyUser>(CriteriaOperator.Parse("[Oid] = CurrentUserId()"));
private DateTime _CreatedOn;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("DisplayFormat", "{0:g}")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
public DateTime CreatedOn
{
get { return _CreatedOn; }
set { SetPropertyValue<DateTime>(nameof(CreatedOn), ref _CreatedOn, value); }
}
private DateTime _ModifiedOn;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("DisplayFormat", "{0:g}")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
public DateTime ModifiedOn
{
get { return _ModifiedOn; }
set { SetPropertyValue<DateTime>(nameof(ModifiedOn), ref _ModifiedOn, value); }
}
private DateTime _DeletedOn;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("DisplayFormat", "{0:g}")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
public DateTime DeletedOn
{
get { return _DeletedOn; }
set { SetPropertyValue<DateTime>(nameof(DeletedOn), ref _DeletedOn, value); }
}
private PermissionPolicyUser _CreatedBy;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
[SearchMemberOptions(SearchMemberMode.Exclude)]
public PermissionPolicyUser CreatedBy
{
get { return _CreatedBy; }
set { SetPropertyValue<PermissionPolicyUser>(nameof(CreatedBy), ref _CreatedBy, value); }
}
private PermissionPolicyUser _LastModifiedBy;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
[SearchMemberOptions(SearchMemberMode.Exclude)]
public PermissionPolicyUser LastModifiedBy
{
get { return _LastModifiedBy; }
set { SetPropertyValue<PermissionPolicyUser>(nameof(LastModifiedBy), ref _LastModifiedBy, value); }
}
private PermissionPolicyUser _DeletedBy;
[NonCloneable]
[EditorAlias("ReadOnlyLabelPropertyEditor")]
[ModelDefault("AllowEdit", "False")]
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
[SearchMemberOptions(SearchMemberMode.Exclude)]
public PermissionPolicyUser DeletedBy
{
get { return _DeletedBy; }
set { SetPropertyValue<PermissionPolicyUser>(nameof(DeletedBy), ref _DeletedBy, value); }
}
}
Use the SingletonBO attribute on a business object to always show a Detail View instead of a List View. When you create your business object, you should plan to only ever have one instance of it in your database. Navigating to the List View will automatically show the Detail View instead.
[SingletonBO]
public class ProgramOptions : BaseObject
{
...
}
The ISingletonBO attribute was removed and should be replaced with the SingletonBO attribute.
Use the SingletonBO attribute on a business object to always show a Detail View instead of a List View. When you create your business object, you should plan to only ever have one instance of it in your database. Navigating to the List View will automatically show the Detail View instead.
[SingletonBO]
public class ProgramOptions : BaseObject
{
...
}
The ISingletonBO attribute was removed and should be replaced with the SingletonBO attribute.
If your application supports multiple languages and you want to minimize the amount of translation that happens in the model file, you can utilize the ActionLocalization and LocalizedText attributes.
[LocalizedText("MyExceptionText", "I told you this doesn't do anything...")]
public class ActionLocalizationSampleController : ViewController
{
[ActionLocalization(Caption = "My Action Caption", ConfirmationMessage = "This button doesn't do anything. Do you want to continue?", ToolTip = "I'm boring!")] //Default Text
[ActionLocalization(Caption = "Moja Etykieta Akcji", ConfirmationMessage = "Ten przycisk nic nie robi. Czy chcesz kontynuować?", ToolTip = "Jestem nudny!", Language = "pl-PL")] //Polish Localization
[ActionLocalization(Caption = "Titulo de mi acción", ConfirmationMessage = "Este boton no hace nada. Desea continuar?", ToolTip = "Estoy aburrido!", Language = "es")] //Spanish Localization
public SimpleAction MyAction { get; private set; }
public ActionLocalizationSampleController()
{
MyAction = new SimpleAction(this, nameof(MyAction), DevExpress.Persistent.Base.PredefinedCategory.Unspecified);
MyAction.Execute += MyAction_Execute;
}
private void MyAction_Execute(object sender, SimpleActionExecuteEventArgs e)
{
throw new UserFriendlyException(this.GetLocalizedText("MyExceptionText"));
}
}
| Application | Llamachant Framework | Values |
|---|---|---|
| Localization | ||
| Controllers | ||
| ActionLocalizationSampleController | ||
| MyExceptionText | Value | String |
If your application supports multiple languages and you want to minimize the amount of translation that happens in the model file, you can utilize the ActionLocalization and LocalizedText attributes.
[LocalizedText("MyExceptionText", "I told you this doesn't do anything...")]
public class ActionLocalizationSampleController : ViewController
{
[ActionLocalization(Caption = "My Action Caption", ConfirmationMessage = "This button doesn't do anything. Do you want to continue?", ToolTip = "I'm boring!")] //Default Text
[ActionLocalization(Caption = "Moja Etykieta Akcji", ConfirmationMessage = "Ten przycisk nic nie robi. Czy chcesz kontynuować?", ToolTip = "Jestem nudny!", Language = "pl-PL")] //Polish Localization
[ActionLocalization(Caption = "Titulo de mi acción", ConfirmationMessage = "Este boton no hace nada. Desea continuar?", ToolTip = "Estoy aburrido!", Language = "es")] //Spanish Localization
public SimpleAction MyAction { get; private set; }
public ActionLocalizationSampleController()
{
MyAction = new SimpleAction(this, nameof(MyAction), DevExpress.Persistent.Base.PredefinedCategory.Unspecified);
MyAction.Execute += MyAction_Execute;
}
private void MyAction_Execute(object sender, SimpleActionExecuteEventArgs e)
{
throw new UserFriendlyException(this.GetLocalizedText("MyExceptionText"));
}
}
| Application | Llamachant Framework | Values |
|---|---|---|
| Localization | ||
| Controllers | ||
| ActionLocalizationSampleController | ||
| MyExceptionText | Value | String |
This feature allows you to specify the preferred width and/or height of popup windows in Blazor applications. Because these applications are responsive, this module also takes into account a minimum screen width so mobile versions remain at 100%.
This feature requires the Blazor specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowPopupWindowSizes | True / False | |
| PopupWindowSizeDefaultWidth | Integer (vw / %) | |
| PopupWindowSizeMinWidth | Integer (Pixels) | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_DetailView | PopupWindowHeight | Integer (vh / %) |
| PopupWindowWidth | Integer (vw / %) |
This feature allows you to specify the preferred width and/or height of popup windows in Blazor applications. Because these applications are responsive, this module also takes into account a minimum screen width so mobile versions remain at 100%.
This feature requires the Blazor specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowPopupWindowSizes | True / False | |
| PopupWindowSizeDefaultWidth | Integer (vw / %) | |
| PopupWindowSizeMinWidth | Integer (Pixels) | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_DetailView | PopupWindowHeight | Integer (vh / %) |
| PopupWindowWidth | Integer (vw / %) |
Give your users the ability to change the application font size. This option adds a Font Size action to the View tab by default where a list of pre-defined sizes can be selected. The list of sizes can be edited in the model directly, allowing you to adjust the sizes as needed.
This feature requires the Win specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowFontSizeSelection | True / False | |
| FontSizes | ||
| Extra Large | ||
| Large | ||
| Normal | ||
| Small | ||
| Tiny | Caption | String |
| FontSize | double (Point) |
Give your users the ability to change the application font size. This option adds a Font Size action to the View tab by default where a list of pre-defined sizes can be selected. The list of sizes can be edited in the model directly, allowing you to adjust the sizes as needed.
This feature requires the Win specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowFontSizeSelection | True / False | |
| FontSizes | ||
| Extra Large | ||
| Large | ||
| Normal | ||
| Small | ||
| Tiny | Caption | String |
| FontSize | double (Point) |
To make it easier to recognize what kind of object you're opening, enable the ShowTypeNameInOpenObject option in the Model Editor. This will add the object’s type name to the caption when you open it. If you'd like to customize the caption format even further, update the OpenObjectWithCaption text in the Localization items to use your own wording.
This feature requires the Win specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| ShowTypeNameInOpenObject | True / False | |
| Localization | ||
| Texts | ||
| OpenObjectWithCaption | Value | String - Example: Open Focused {0} |
To make it easier to recognize what kind of object you're opening, enable the ShowTypeNameInOpenObject option in the Model Editor. This will add the object’s type name to the caption when you open it. If you'd like to customize the caption format even further, update the OpenObjectWithCaption text in the Localization items to use your own wording.
This feature requires the Win specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| ShowTypeNameInOpenObject | True / False | |
| Localization | ||
| Texts | ||
| OpenObjectWithCaption | Value | String - Example: Open Focused {0} |
Allows toggling the footer on GridListEditors and TreeListEditors within a WinForms application.
This feature requires the Win specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowSummaryPanelMenuItem | True / False | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | AllowSummaryPanelMenuItem | True / False |
Allows toggling the footer on GridListEditors and TreeListEditors within a WinForms application.
This feature requires the Win specific module to be registered in your application
| Application | Llamachant Framework | Values |
|---|---|---|
| AllowSummaryPanelMenuItem | True / False | |
| Views | ||
| Llamachant.ExpressApp | ||
| BusinessObject | ||
| BusinessObject_ListView | AllowSummaryPanelMenuItem | True / False |