这章主要说插件的菜单,可以说菜单是最核心的部分,前面我们已经实现了Document添加,现在主要就是生成具有层级关系的菜单,以及把菜单跟我们自定义的Document关联起来,也就是MenuPart->View->Model的关联,菜单的实现部分我也是网上参照别人的来实现的,由于代码比较多,我就抽一些重要的来说,其他的只能靠各位自己去体会了,不明白的可以照葫芦画瓢,这菜单部分可以直接抽出来用的,我们不需要明白它内部是怎么实现的,能用就行了,其实有些地方我也没有深入去了解,我们主要的任务是把现有的技术融合成一个可用的插件平台,技术的细节以后有时间再讨论。。。
额外提示所有关于UI的操作都是以绑定的方式实现的,如果不熟悉WPF以及MVVM模式可能会难以理解 [BY Zengg]
运行结果:
可以看到我们已经能做到通过菜单来控制插件的显示以及关闭,插件平台已经初具雏形
UICore部分
涉及到核心的项目结构部分:
IPart 定义了菜单的基本属性,主要的方法是 void Execute(),这是单击菜单后的执行方法, 之后我们得把Show出Document的动作写入Execute方法里面。
1 namespace UICoreFramework 2 { 3 /// <summary> 4 /// Denotes an instance which can be executed. 5 /// </summary> 6 public interface IExecutable 7 { 8 bool CanExecute { get; } 9 void Execute(); 10 } 11 12 /// <summary> 13 /// Denotes an instance which can be checked. 14 /// </summary> 15 public interface ICheckable 16 { 17 bool IsCheckable { get; } 18 bool IsChecked { get; set; } 19 } 20 21 /// <summary> 22 /// Denotes a small UI widget that can display and interact. 23 /// </summary> 24 public interface IPart : ILocalizableDisplay, IExecutable, IActivate, IDeactivate 25 { 26 string InputGestureText { get; set; } 27 28 void OnAttached(); 29 30 string Icon { get; set; } 31 32 bool IsVisible { get; set; } 33 } 34 35 /// <summary> 36 /// Concrete <see cref="IPart"/> which denotes a <see cref="System.Window.Controls.MenuItem"/> instance. 37 /// </summary> 38 public interface IMenuPart : IPart, ISeparaterPart, ICheckable 39 { 40 41 } 42 43 /// <summary> 44 /// Denotes a <see cref="System.Window.Controls.Separater"/> instance. 45 /// </summary> 46 public interface ISeparaterPart 47 { 48 bool IsSeparator { get; } 49 } 50 51 /// <summary> 52 /// Denotes a manager class that manage the <see cref="IPart"/>s. 53 /// </summary> 54 public interface IPartManager<T> where T : IPart 55 { 56 IObservableCollection<T> Items { get; } 57 } 58 59 /// <summary> 60 /// Denotes a manager node that holds the <see cref="IObservableCollection"/> item. 61 /// </summary> 62 public interface IObservableParent<T> 63 { 64 IObservableCollection<T> Items { get; } 65 } 66 }
PartBase IPart的抽象类主要实现了IPart接口以及一些共同的抽象函数。
namespace UICoreFramework { /// <summary> /// Base <see cref="IPart"/> class for various implementations of <see cref="IPart"/>. /// </summary> public abstract class PartBase : PropertyChangedBase, IPart { protected PartBase() :this(null) { } protected PartBase(string name) { DisplayName = name; this.Name = name ?? GetType().Name.Replace("Part", string.Empty); this.execute = ((i) => { }); this.canExecute = (() => IsActive); } public PartBase(string name, System.Action<PartBase> execute, Func<bool> canExecute = null) : this(name) { this.execute = execute ?? ((i) => { }); this.canExecute = canExecute ?? (() => IsActive); } private string name; public string Name { get { return name; } protected set { name = value; NotifyOfPropertyChange(() => Name); } } private string displayName; public string DisplayName { get { return displayName; } set { displayName = value; NotifyOfPropertyChange(() => DisplayName); } } private string icon; public string Icon { get { return icon; } set { icon = value; NotifyOfPropertyChange(() => Icon); } } private string inputGestureText; public string InputGestureText { get { return inputGestureText; } set { inputGestureText = value; NotifyOfPropertyChange(() => InputGestureText); } } private bool isVisible = true; public bool IsVisible { get { return isVisible; } set { isVisible = value; NotifyOfPropertyChange(() => IsVisible); } } public virtual void OnAttached() { } #region IExecutable private readonly System.Action<PartBase> execute; /// <summary> /// The action associated to the ActionItem /// </summary> public virtual void Execute() { this.execute(this); } private readonly Func<bool> canExecute; /// <summary> /// Calls the underlying canExecute function. /// </summary> public virtual bool CanExecute { get { return canExecute(); } } #endregion #region Activation & Deactivation public event EventHandler<ActivationEventArgs> Activated; public event EventHandler<DeactivationEventArgs> AttemptingDeactivation; public event EventHandler<DeactivationEventArgs> Deactivated; private bool isActive = true; public bool IsActive { get { return isActive; } } public void Activate() { if (IsActive) return; isActive = true; OnActivate(); if (Activated != null) Activated(this, new ActivationEventArgs { WasInitialized = false }); NotifyOfPropertyChange(() => CanExecute); } protected virtual void OnActivate() { } public virtual void Deactivate(bool close) { if (!IsActive) return; if (AttemptingDeactivation != null) AttemptingDeactivation(this, new DeactivationEventArgs { WasClosed = close }); isActive = false; OnDeactivate(close); NotifyOfPropertyChange(() => CanExecute); if (Deactivated != null) Deactivated(this, new DeactivationEventArgs { WasClosed = close }); } protected virtual void OnDeactivate(bool close) { } #endregion #region IHandle<LanguageChangedEventArgs> Members //public void Handle(LanguageChangedMessage message) //{ // this.UpdateDisplayName(); //} #endregion } }