-
Notifications
You must be signed in to change notification settings - Fork 0
Advanced scenarios and examples
One key benefit of the introduction of a controller is that you can control the concrete screen that is created, and how it is going to be shaped.
The root of these variations is located in the signature of IControllerManager.ShowWindowAsync
and IControllerManager.ShowDialogAsync
:
Task<TController> ShowWindowAsync<TControll>(**object options**, object context, IDictionary<string, string> settings);
Task<TController> ShowDialogAsync<TControll>(**object options**, object context, IDictionary<string, string> settings);
The parameters context
and settings
are known from the underlying Caliburn.Micro
implementation, but options
is the parameter you can base your decisions on.
With overriding GetScreenType
one can simply control the creation (and displaying) of screens according to options
:
using Caliburn.Micro;
using Caliburn.Micro.Contrib.Controller;
using Jetbrains.Annotations;
public class MainController : ControllerBase<MainViewModel>
{
public MainController([NotNull] IScreenFactory screenFactory,
[NotNull] [ItemNotNull] params IRoutine[] routines)
: base(screenFactory,
routines) {}
[NotNull]
public override Type GetScreenType([CanBeNull] object options = null)
{
return base.GetScreenType(options);
}
}
Just be aware that the returned Type
-instance shall not be an interface, and has to implement IScreen
.
If you simply want to inject some properties, but leave the creation of the screen intact, override BuildUp
:
using Caliburn.Micro;
using Caliburn.Micro.Contrib.Controller;
using Jetbrains.Annotations;
public class MainController : ControllerBase<MainViewModel>
{
public MainController([NotNull] IScreenFactory screenFactory,
[NotNull] [ItemNotNull] params IRoutine[] routines)
: base(screenFactory,
routines) {}
[NotNull]
public override MainViewModel BuildUp([NotNull] MainViewModel screen,
[CanBeNull] object options = null)
{
var creationOptions = options as CreationOptions;
if (creationOptions != null)
{
screen.Name = creationOptions.Name;
}
return screen;
}
public sealed class CreationOptions
{
[CanBeNull]
public string Name { get; set; }
}
}
// Usage:
// var creationOptions = new MainController.CreationOptions
// {
// Name = "Joe Doe"
// };
// var controllerManager = IoC.Get<IControllerManager>();
// controllerManager.ShowWindowAsync<MainController>(creationOptions);
You can declare interest in a specific Controller routine
in your Controller
's constructor:
using Caliburn.Micro.Contrib.Controller;
using JetBrains.Annotations;
public class MainController : ControllerBase<MainViewModel>
{
/// <exception cref="ArgumentNullException"><paramref name="defaultDisplayNameRoutine" /> is <see langword="null" /></exception>
public MainController([NotNull] DefaultDisplayNameRoutine defaultDisplayNameRoutine,
[NotNull] IScreenFactory screenFactory,
[NotNull] [ItemNotNull] params IRoutine[] routines)
: base(screenFactory,
routines)
{
if (defaultDisplayNameRoutine == null)
{
throw new ArgumentNullException(nameof(defaultDisplayNameRoutine));
}
this.DefaultDisplayNameRoutine = this.RegisterRoutine(defaultDisplayNameRoutine);
}
[NotNull]
private DefaultDisplayNameRoutine DefaultDisplayNameRoutine { get; }
}
Instead of calling the
base
-ctor with theController routine
in question, set the instance to a local member and callthis.RegisterRoutine(controllerRoutine)
.
Injecting additional behavior into the View Model
can be useful for multiple reasons, such as writing a Controller routine
that should automagically extend the View Model
(see BlockingRoutine
for an actual example).
Mixins can be defined on a Controller routine
:
using System.Reflection.Emit;
using Caliburn.Micro.Contrib.Controller;
using JetBrains.Annotations;
public class SomeControllerRoutine : ControllerRoutineBase,
IScreenMixin<SomeControllerRoutine.Mixin>,
IScreenMixin<SomeControllerRoutine.IMixin>,
IScreenAttributesMixin
{
public interface IMixin
{
string SomeProperty { get; set; }
void SomeMethod();
}
public class Mixin : IMixin
{
public string SomeProperty { get; set; }
public void SomeMethod() { /* ... */ }
}
[Pure]
[NotNull]
[ItemNotNull]
public CustomAttributeBuilder[] GetCustomAttributeBuilders()
{
/* ... */
}
}
Caution: Please be aware, that you have to implement additional
NotifyOfPropertyChange
-calls in yourController routine
, as DynamicProxy cannot intercept events at this very moment.
Caution: You can define additional attributes to be injected on the class'-level but not on member-level. Read more about CustomAttributeBuilder.
using Caliburn.Micro;
using Caliburn.Micro.Contrib.Controller;
using JetBrains.Annotations;
public abstract class MainViewModel : Screen
{
public sealed class Close {}
}
public class MainController : ControllerBase<MainViewModel>,
Intercept<MainViewModel>.IHandle<MainViewModel.Close>
{
public MainController([NotNull] IScreenFactory screenFactory,
[NotNull] [ItemNotNull] params IRoutine[] routines)
: base(screenFactory,
routines) {}
[UsedImplicitly]
[InterceptProxyMethod(CallBase = false)]
public void Handle([NotNull] MainViewModel mainViewModel,
[NotNull] MainViewModel.Close message)
{
mainViewModel.TryClose();
}
}