UsingZetBox
Using the ZetBox
This chapter describes common tasks and how to use the ZetBox.
Creating the UI from meta data
Properties
The default order of properties is defined by
- The order within the data type
- Inheritance: derived class first
Properties are grouped by their summary tags. Tags are separated by a comma ','. A underline '_' will be translated in a space. The order of tags is defined:
- Summary
- Main
- all other
- Meta
The tag "Hidden" is only visible to Administrators. The Tag "Main", if not available "Summary", is selected first when the object has been opened.
Tags can be translated. The translated tag is only used in the title of a property group. Thus tags should be entered in English.
Methods
Methods are not visible by default. The property "IsDisplayable" controls this.
A Method can also have category tags. Methods will be grouped in a Menu. See Properties for details.
"Show by Properties" is a way to display a Method in the Toolbar of a list property. Note: The selected item is not passed to the method.
Using custom ViewModels and Views for the UI
TODO:
Styling the UI
Styles for basic controls are defined by the zetbox. They can be overridden by registering own styles:
[Feature(NotOnFallback = true)]
public class MyWpfModule : Module
{
protected override void Load(ContainerBuilder moduleBuilder)
{
base.Load(moduleBuilder);
try
{
moduleBuilder
.RegisterInstance<ResourceDictionary>(new ResourceDictionary() { Source = new Uri("/MyProject.App.Client.WPF;component/View/Common/MyProjectStyles.xaml", UriKind.Relative) })
.WithMetadata(WPFHelper.RESOURCE_DICTIONARY_KIND, WPFHelper.RESOURCE_DICTIONARY_STYLE);
moduleBuilder
.RegisterInstance<ResourceDictionary>(new ResourceDictionary() { Source = new Uri("/MyProject.App.Client.WPF;component/View/Common/MyProjectViews.xaml", UriKind.Relative) })
.WithMetadata(WPFHelper.RESOURCE_DICTIONARY_KIND, WPFHelper.RESOURCE_DICTIONARY_VIEW);
}
catch (Exception ex)
{
Logging.Client.Warn("Unable to register MyProject styles", ex);
}
...
}
}
See also: https://github.com/daszat/zetbox/tree/master/Zetbox.Client.WPF/Styles
These styles can be applied to customize the UI:
AreaGroup1 - an Area level 1
- AreaGroup1TabControl - style for tab controls
- AreaGroup1TabItem - style for tab items
- Area1Expander - style for expanders
- AreaGroup1GroupBox - style for group boxes
- AreaGroup1BorderStyle - style for borders
See https://github.com/daszat/zetbox/blob/master/Zetbox.Client.WPF/Styles/DefaultViews.xaml for detailed definitions
ItemGroup1 - an ItemGroup level 1
- ItemGroup1TabControl - style for tab controls
- ItemGroup1TabItem - style for tab items
- Item1Expander - style for expanders
- ItemGroup1GroupBox - style for group boxes
- ItemGroup1BorderStyle - style for borders
See https://github.com/daszat/zetbox/blob/master/Zetbox.Client.WPF/Styles/DefaultViews.xaml for detailed definitions
These Margins and Paddings are defined:
- AreaGroup1Margin
- AreaGroup1Padding
- ItemGroup1Margin
- ItemGroup1Padding
- ItemMargin
- DialogMargin
These Font-Sizes are defined:
- BigFontSize
- LargeFontSize
- NormalFontSize
- SmallFontSize
To enlarge fonts global, override these styles like described earlier.
Buttons:
- ImageButton - to add an image to ctrls:CommandButton
- ImageOnlyButton - ctrls:CommandButton only with an image
- LinkButton - a button styled as a hyperlink
- ImageToolbarButton - to add an image to ctrls:CommandButton in toolbars
- ImageOnlyToolbarButton - ctrls:CommandButton in tollbars only with an image
Other styles:
- zbTitle - for a TextBlock, used as a title
Custom code
Action classes
To implement custom actions the implementing class has to fulfil some conditions
- It has to be in the same namespace as the class
- The class name must end with Actions to avoid naming collisions
- the class must be decorated with the [Implementor] attribute
- the class can either be static or can provide a constructor with autofac dependencies
Static action class
namespace Zetbox.App.Base
{
[Implementor]
public static class PropertyActions
{
}
}
With dependencies
namespace Zetbox.App.Base
{
[Implementor]
public class DataTypeActions
{
private static IViewModelFactory _vmf;
private static IFrozenContext _frozenCtx;
public DataTypeActions(IViewModelFactory vmf, IFrozenContext frozenCtx)
{
if (vmf == null) throw new ArgumentNullException("vmf");
if (frozenCtx == null) throw new ArgumentNullException("frozenCtx");
_vmf = vmf;
_frozenCtx = frozenCtx;
}
}
}
Methods
The best way to implement methods is to use the template provided by the module editor.
- the method must be decorated with the [Invocation] attribute.
- the method must be static
Examples:
[Invocation]
public static void NotifyCreated(DateRangeFilterConfiguration obj)
{
}
[Invocation]
public static void NotifyPreSave(Event obj)
{
}
[Invocation]
public static void NotifyDeleting(DataType obj)
{
}
[Invocation]
public static void AddProperty(DataType obj, MethodReturnEventArgs<Zetbox.App.Base.Property> e)
{
}
The UI can check, if a method can be invoked. To provide the UI with information about that fact, implement *CanExec and CanExecReason methods
[Invocation]
public static void Upload(File obj)
{
}
[Invocation]
public static void UploadCanExec(ImportedFile obj, MethodReturnEventArgs<bool> e)
{
e.Result = obj.Blob == null;
}
[Invocation]
public static void UploadCanExecReason(ImportedFile obj, MethodReturnEventArgs<string> e)
{
e.Result = "Changing blob on imported files is not allowed";
}
Getter/Setter
Dialogs
Sometimes it is necessary to show a Dialog. For example to select something or to edit some details.
Usage is simple, just create a SimpleDataObjectEditorTaskViewModel, pass the ViewModel (can be any view model) to edit and call ShowDialog.
var dlg = ViewModelFactory
.CreateViewModel<SimpleDataObjectEditorTaskViewModel.Factory>()
.Invoke(DataContext, this, item);
ViewModelFactory.ShowDialog(dlg);
If the user should chose from a list, the DataObjectSelectionTaskViewModel can be used:
var selectionTask = ViewModelFactory
.CreateViewModel<DataObjectSelectionTaskViewModel.Factory>()
.Invoke(
DataContext,
this,
typeof(Projekt).GetObjectClass(FrozenContext),
null,
(objs) =>
{
if (objs != null)
{
var prj = (Projekt)objs.First().Object;
...
}
},
null);
selectionTask.ListViewModel.AllowDelete = false;
selectionTask.ListViewModel.AllowOpen = false;
selectionTask.ListViewModel.AllowAddNew = true;
ViewModelFactory.ShowDialog(selectionTask);
The create a fully customized dialog you can use the DialogCreator
using Zetbox.Client.GUI;
var dlg = ViewModelFactory.CreateDialog(DataContext, CalendarResources.DlgDateRangeTitle)
.AddDateTime("from", CalendarResources.FromLabel, DateTime.Today)
.AddDateTime("to", CalendarResources.UntilLabel, DateTime.Today);
dlg.Show((values) =>
{
var from = ((DateTime)values["from"]).Date;
var to = ((DateTime)values["to"]).Date.AddDays(1);
...
});
Translations
String can be translated by the IAssetManager. The AssetManager is also provided on each ViewModel.
public class DataTypeViewModel : ...
{
public override string Name
{
get
{
if (_dataType.Module != null)
return Assets.GetString(_dataType.Module, ZetboxAssetKeys.DataTypes, ZetboxAssetKeys.ConstructNameKey(_dataType), _dataType.Name);
else
return _dataType.Name;
}
}
}
[Implementor]
public class MethodActions
{
private static IAssetsManager _assets;
public MethodActions(IAssetsManager assets)
{
_assets = assets;
}
[Invocation]
public static void GetLabel(Zetbox.App.Base.Method obj, MethodReturnEventArgs<System.String> e)
{
e.Result = !string.IsNullOrEmpty(obj.Label) ? obj.Label : obj.Name;
if (obj.Module == null || obj.ObjectClass == null)
return;
e.Result = _assets.GetString(obj.Module, ZetboxAssetKeys.ConstructBaseName(obj), ZetboxAssetKeys.ConstructLabelKey(obj), e.Result);
}
}