mirror of https://github.com/AMT-Cheif/Stylet.git
231 lines
7.3 KiB
C#
231 lines
7.3 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
|
|
namespace Stylet
|
|
{
|
|
/// <summary>
|
|
/// Implementation of IScreen. Useful as a base class for your ViewModels
|
|
/// </summary>
|
|
public class Screen : ValidatingModelBase, IScreen
|
|
{
|
|
/// <summary>
|
|
/// Create a new Screen instance (without setting up a validator)
|
|
/// </summary>
|
|
public Screen() : this(null) { }
|
|
|
|
/// <summary>
|
|
/// Create a new screen instance, which can validate properties using the given validator
|
|
/// </summary>
|
|
/// <param name="validator">Validator to use</param>
|
|
public Screen(IModelValidator validator) : base(validator)
|
|
{
|
|
this.DisplayName = this.GetType().FullName;
|
|
}
|
|
|
|
#region IHaveDisplayName
|
|
|
|
private string _displayName;
|
|
|
|
/// <summary>
|
|
/// Name associated with this ViewModel. Shown e.g. in a window's title bar, or as a tab's displayName
|
|
/// </summary>
|
|
public virtual string DisplayName
|
|
{
|
|
get { return this._displayName; }
|
|
set { SetAndNotify(ref this._displayName, value); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IActivate
|
|
|
|
/// <summary>
|
|
/// Fired whenever the Screen is activated
|
|
/// </summary>
|
|
public event EventHandler<ActivationEventArgs> Activated;
|
|
|
|
private bool hasBeenActivatedEver;
|
|
|
|
private bool _isActive;
|
|
/// <summary>
|
|
/// True if this Screen is currently active
|
|
/// </summary>
|
|
public bool IsActive
|
|
{
|
|
get { return this._isActive; }
|
|
set { SetAndNotify(ref this._isActive, value); }
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "As this is a framework type, don't want to make it too easy for users to call this method")]
|
|
void IActivate.Activate()
|
|
{
|
|
if (this.IsActive)
|
|
return;
|
|
|
|
this.IsActive = true;
|
|
this.isClosed = false;
|
|
|
|
if (!this.hasBeenActivatedEver)
|
|
this.OnInitialActivate();
|
|
this.hasBeenActivatedEver = true;
|
|
|
|
this.OnActivate();
|
|
|
|
var handler = this.Activated;
|
|
if (handler != null)
|
|
handler(this, new ActivationEventArgs());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called the very first time this Screen is activated, and never again
|
|
/// </summary>
|
|
protected virtual void OnInitialActivate() { }
|
|
|
|
/// <summary>
|
|
/// Called every time this screen is activated
|
|
/// </summary>
|
|
protected virtual void OnActivate() { }
|
|
|
|
#endregion
|
|
|
|
#region IDeactivate
|
|
|
|
/// <summary>
|
|
/// Fired whenever the Screen is deactivated
|
|
/// </summary>
|
|
public event EventHandler<DeactivationEventArgs> Deactivated;
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope = "member", Target = "Stylet.Screen.#Stylet.IDeactivate.Deactivate()", Justification = "As this is a framework type, don't want to make it too easy for users to call this method")]
|
|
void IDeactivate.Deactivate()
|
|
{
|
|
if (!this.IsActive)
|
|
return;
|
|
|
|
this.IsActive = false;
|
|
this.isClosed = false;
|
|
|
|
this.OnDeactivate();
|
|
|
|
var handler = this.Deactivated;
|
|
if (handler != null)
|
|
handler(this, new DeactivationEventArgs());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called every time this screen is deactivated
|
|
/// </summary>
|
|
protected virtual void OnDeactivate() { }
|
|
|
|
#endregion
|
|
|
|
#region IClose
|
|
|
|
private bool isClosed = false;
|
|
|
|
/// <summary>
|
|
/// Called whenever this Screen is closed
|
|
/// </summary>
|
|
public event EventHandler<CloseEventArgs> Closed;
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "As this is a framework type, don't want to make it too easy for users to call this method")]
|
|
void IClose.Close()
|
|
{
|
|
if (this.isClosed)
|
|
return;
|
|
|
|
// This will early-exit if it's already deactive
|
|
((IDeactivate)this).Deactivate();
|
|
|
|
this.View = null;
|
|
this.isClosed = true;
|
|
|
|
this.OnClose();
|
|
|
|
var handler = this.Closed;
|
|
if (handler != null)
|
|
handler(this, new CloseEventArgs());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when this screen is closed
|
|
/// </summary>
|
|
protected virtual void OnClose() { }
|
|
|
|
#endregion
|
|
|
|
#region IViewAware
|
|
|
|
/// <summary>
|
|
/// View attached to this ViewModel, if any. Using this should be a last resort
|
|
/// </summary>
|
|
public UIElement View { get; private set; }
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "As this is a framework type, don't want to make it too easy for users to call this method")]
|
|
void IViewAware.AttachView(UIElement view)
|
|
{
|
|
if (this.View != null)
|
|
throw new InvalidOperationException(String.Format("Tried to attach View {0} to ViewModel {1}, but it already has a view attached", view.GetType().Name, this.GetType().Name));
|
|
|
|
this.View = view;
|
|
|
|
var viewAsFrameworkElement = view as FrameworkElement;
|
|
if (viewAsFrameworkElement != null)
|
|
{
|
|
if (viewAsFrameworkElement.IsLoaded)
|
|
this.OnViewLoaded();
|
|
else
|
|
viewAsFrameworkElement.Loaded += (o, e) => this.OnViewLoaded();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the view attaches to the Screen loads
|
|
/// </summary>
|
|
protected virtual void OnViewLoaded() { }
|
|
|
|
#endregion
|
|
|
|
#region IChild
|
|
|
|
private object _parent;
|
|
/// <summary>
|
|
/// Parent conductor of this screen. Used to TryClose to request a closure
|
|
/// </summary>
|
|
public object Parent
|
|
{
|
|
get { return this._parent; }
|
|
set { SetAndNotify(ref this._parent, value); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IGuardClose
|
|
|
|
/// <summary>
|
|
/// Called when a conductor wants to know whether this screen can close.
|
|
/// </summary>
|
|
/// <returns>A task returning true (can close) or false (can't close)</returns>
|
|
public virtual Task<bool> CanCloseAsync()
|
|
{
|
|
return Task.FromResult(true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Request that the conductor responsible for this screen close it
|
|
/// </summary>
|
|
/// <param name="dialogResult"></param>
|
|
public virtual void TryClose(bool? dialogResult = null)
|
|
{
|
|
var conductor = this.Parent as IChildDelegate;
|
|
if (conductor != null)
|
|
conductor.CloseItem(this, dialogResult);
|
|
else
|
|
throw new InvalidOperationException(String.Format("Unable to close ViewModel {0} as it must have a conductor as a parent (note that windows and dialogs automatically have such a parent)", this.GetType().Name));
|
|
}
|
|
}
|
|
}
|