protected override void OnLoad(EventArgs args) { base.OnLoad(args); UpdateTitle(); // Step 1. Bind apriori known actions Action <ToolStripItem, Func <ICommand> > bind = (mi, fcmd) => Ctx.BindCommand((ToolStripMenuItem)mi, fcmd); bind(_vaultNew, () => new VaultNewCommand(Ctx)); bind(_vaultOpen, () => new VaultOpenCommand(Ctx)); bind(_vaultSave, () => new VaultSaveCommand(Ctx)); bind(_vaultImport, () => new VaultImportCommand(Ctx)); bind(_vaultExport, () => new VaultExportCommand(Ctx)); bind(_vaultExit, () => new VaultExitCommand(Ctx)); bind(_editUndo, () => new UndoCommand(Ctx)); bind(_editRedo, () => new RedoCommand(Ctx)); bind(_branchNew, () => new BranchNewCommand(Ctx)); bind(_branchNewPopup, () => new BranchNewCommand(Ctx)); bind(_branchEditMetadata, () => new BranchEditMetadataStartCommand(Ctx)); bind(_branchEditMetadataPopup, () => new BranchEditMetadataStartCommand(Ctx)); bind(_branchDelete, () => new BranchDeleteCommand(Ctx)); bind(_branchDeletePopup, () => new BranchDeleteCommand(Ctx)); bind(_branchRename, () => new BranchRenameStartCommand(Ctx)); bind(_branchRenamePopup, () => new BranchRenameStartCommand(Ctx)); bind(_branchMoveUp, () => new BranchMoveUpCommand(Ctx)); bind(_branchMoveUpPopup, () => new BranchMoveUpCommand(Ctx)); bind(_branchMoveDown, () => new BranchMoveDownCommand(Ctx)); bind(_branchMoveDownPopup, () => new BranchMoveDownCommand(Ctx)); bind(_valueEdit, () => new ValueEditStartCommand(Ctx)); bind(_valueEditPopup, () => new ValueEditStartCommand(Ctx)); bind(_valueEditMetadata, () => new ValueEditMetadataStartCommand(Ctx)); bind(_valueEditMetadataPopup, () => new ValueEditMetadataStartCommand(Ctx)); bind(_valueRename, () => new ValueRenameStartCommand(Ctx)); bind(_valueRenamePopup, () => new ValueRenameStartCommand(Ctx)); bind(_valueDelete, () => new ValueDeleteCommand(Ctx)); bind(_valueDeletePopup, () => new ValueDeleteCommand(Ctx)); bind(_editCut, () => new CutCommand(Ctx)); bind(_editCopy, () => new CopyCommand(Ctx)); bind(_editPaste, () => new PasteCommand(Ctx)); bind(_branchCutPopup, () => new BranchCutCommand(Ctx)); bind(_branchCopyPopup, () => new BranchCopyCommand(Ctx)); bind(_branchPastePopup, () => new BranchPasteCommand(Ctx)); bind(_valueCutPopup, () => new ValueCutCommand(Ctx)); bind(_valueCopyPopup, () => new ValueCopyCommand(Ctx)); bind(_valuePastePopup, () => new ValuePasteCommand(Ctx)); bind(_valueCutPopup2, () => new ValueCutCommand(Ctx)); bind(_valueCopyPopup2, () => new ValueCopyCommand(Ctx)); bind(_valuePastePopup2, () => new ValuePasteCommand(Ctx)); // Step 2. Generate and bind value creation actions Action <ToolStripItemCollection> generateAndBind = coll => { var generated = ContentTypes.All.ToDictionary(t => new ToolStripMenuItem(t.LocNewValue) { Tag = t }, t => t); generated.ForEach(kvp => bind(kvp.Key, () => new ValueNewTypedCommand(Ctx, kvp.Value.TypeToken))); var binary = new ToolStripMenuItem(Resources.New_ValueBinary); bind(binary, () => new ValueNewBinaryCommand(Ctx)); var dummy = coll.Cast <ToolStripItem>().Single(item => item.Name.Contains("Dummy")); var index = coll.IndexOf(dummy); dummy.Visible = false; coll.Insert(index, binary); generated.ForEach(kvp => coll.Insert(index, kvp.Key)); }; generateAndBind(_value.DropDownItems); generateAndBind(_branchPopup.Items); generateAndBind(_valuePopup2.Items); // Step 3. Generate and bind view actions var map = new Dictionary <String, ToolStripMenuItem>(); VaultViewFactories.All.OrderBy(v => v.LocName).ForEach(v => { var nameTemplate = Resources.Views_MenuItem_Template; var moduleVersion = v.Type.Assembly.GetName().Version.ToString(); var miName = String.Format(nameTemplate, v.LocName, moduleVersion); var mi = new ToolStripMenuItem(miName); map.Add(v.Name, mi); _views.DropDownItems.Add(mi); bind(mi, () => new ViewToggleCommand(Ctx, v.Name)); }); _views.Tag = map; // hack // rearrange menu items on view stack changes: push... Ctx.Views.ItemPushed += (o, e) => { var mi = map[e.Item.Name]; mi.Checked = true; _views.DropDownItems.Remove(mi); var iofSep = _views.DropDownItems.IndexOf(_separator13); _views.DropDownItems.Insert(iofSep, mi); }; // ...and pop Ctx.Views.ItemPopped += (o, e) => { var mi = map[e.Item.Name]; mi.Checked = false; _views.DropDownItems.Remove(mi); var iofDummy = _views.DropDownItems.IndexOf(_viewsAvailableDummy); var lo = iofDummy; var hi = _views.DropDownItems.Count; Func <int, String> text = i => i == iofDummy ? "\x0000" : i == _views.DropDownItems.Count ? "\xffff" : _views.DropDownItems[i].Text; while (hi - lo > 1) { var mid = (int)Math.Ceiling((lo + hi) / 2.0); var cmp = String.CompareOrdinal(text(mid), mi.Text); (cmp != 0).AssertTrue(); if (cmp == -1) { lo = mid; } if (cmp == 1) { hi = mid; } } // insert in the exact position to remain sorted _views.DropDownItems.Insert(lo + 1, mi); }; // update visibility of menu parts _commands.AfterUIResync += (o, e) => { var active = Ctx.Views.ToArray(); var available = VaultViewFactories.All.Where(v_av => !active.Any(v_ac => v_ac.Name == v_av.Name)).ToArray(); _views.Visible = active.IsNotEmpty() || available.IsNotEmpty(); _viewsActive.Visible = active.IsNotEmpty(); _separator13.Visible = active.IsNotEmpty() && available.IsNotEmpty(); _viewsAvailable.Visible = available.IsNotEmpty(); var realMenuItems = _views.DropDownItems.OfType <ToolStripMenuItem>() .Except(new[] { _viewsActive, _viewsAvailable }) .Where(mi => !mi.Name.ToLower().Contains("dummy")); _views.Enabled = realMenuItems.Any(mi => mi.Enabled); }; // Step 4. Ensure event sources are always synced with the commands _commands.ResyncUI(); _tree.AfterSelect += (o, e) => _commands.ResyncUI(); _tree.NodeMouseClick += (o, e) => { _tree.SelectedNode = e.Node; _commands.ResyncUI(); }; _list.SelectedIndexChanged += (o, e) => _commands.ResyncUI(); _tree.LostFocus += (o, e) => _commands.ResyncUI(); _tree.GotFocus += (o, e) => _commands.ResyncUI(); _list.LostFocus += (o, e) => _commands.ResyncUI(); _list.GotFocus += (o, e) => _commands.ResyncUI(); // Step 5. Ensure that only one command can be executed at a time Ctx.CommandExecuting += (o, e) => { Ctx.CommandsAllowed = false; _commands.ResyncUI(); }; Ctx.CommandUnexecuting += (o, e) => { Ctx.CommandsAllowed = false; _commands.ResyncUI(); }; Ctx.CommandExecutionCancelled += (o, e) => { Ctx.CommandsAllowed = true; _commands.ResyncUI(); }; Ctx.CommandUnexecutionCancelled += (o, e) => { Ctx.CommandsAllowed = true; _commands.ResyncUI(); }; Ctx.CommandExecuted += (o, e) => { Ctx.CommandsAllowed = true; _commands.ResyncUI(); }; Ctx.CommandUnexecuted += (o, e) => { Ctx.CommandsAllowed = true; _commands.ResyncUI(); }; // Step 6. Setup UI update feedback _tree.AfterSelect += (o, e) => Ctx.RebuildListItems(); Ctx.CommandExecuted += (o, e) => UpdateTitle(); _commands.BeforeUIResync += (o, e) => { if (BeforeUIResync != null) { BeforeUIResync(o, e); } }; _commands.AfterUIResync += (o, e) => { if (AfterUIResync != null) { AfterUIResync(o, e); } }; // Step 7. Load UI extensions _extensions = DataVaultUIExtensions.All.ToArray(); _extensions.ForEach(ext => ext.Initialize(Ctx)); // 8. Now once we're all started, we can proceed to loading vault from initial URI LoadFromInitialUri(); }