| File: System\ComponentModel\Design\DesignerActionPanel.MethodLine.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using System.Reflection; using System.Windows.Forms; namespace System.ComponentModel.Design; internal sealed partial class DesignerActionPanel { private sealed class MethodLine : Line { private DesignerActionList? _actionList; private DesignerActionMethodItem? _methodItem; private readonly MethodItemLinkLabel _linkLabel; private MethodLine(IServiceProvider serviceProvider, DesignerActionPanel actionPanel) : base(serviceProvider, actionPanel) { _linkLabel = new MethodItemLinkLabel { ActiveLinkColor = ActionPanel.ActiveLinkColor, AutoSize = false, BackColor = Color.Transparent, LinkBehavior = LinkBehavior.HoverUnderline, LinkColor = ActionPanel.LinkColor, TextAlign = ContentAlignment.MiddleLeft, UseMnemonic = false, VisitedLinkColor = ActionPanel.LinkColor }; _linkLabel.LinkClicked += OnLinkLabelLinkClicked; AddedControls.Add(_linkLabel); } // _methodItem and _actionList are set in UpdateActionItem, which is always called right after the MethodLine object creation public override string FocusId => $"METHOD:{_actionList!.GetType().FullName}.{_methodItem!.MemberName}"; public override void Focus() { _linkLabel.Focus(); } public override Size LayoutControls(int top, int width, bool measureOnly) { Size linkLabelSize = _linkLabel.GetPreferredSize(new Size(int.MaxValue, int.MaxValue)); if (!measureOnly) { _linkLabel.Location = new Point(LineLeftMargin, top + LineVerticalPadding / 2); _linkLabel.Size = linkLabelSize; } return linkLabelSize + new Size(LineLeftMargin + LineRightMargin, LineVerticalPadding); } private void OnLinkLabelLinkClicked(object? sender, LinkLabelLinkClickedEventArgs e) { Debug.Assert(!ActionPanel.InMethodInvoke, "Nested method invocation"); ActionPanel.InMethodInvoke = true; try { // _methodItem is set in UpdateActionItem, which is always called right after the MethodLine object creation _methodItem!.Invoke(); } catch (Exception ex) { if (ex is TargetInvocationException) { ex = ex.InnerException!; } // NOTE: We had code to rethrow if this was one of [NullReferenceException, StackOverflowException, OutOfMemoryException, // ThreadAbortException]. Removing this rethrow. StackOverflow and ThreadAbort can't be meaningfully caught, and // NullRef and OutOfMemory really shouldn't be caught. Out of these, OOM is the most correct one to call, but OOM is // thrown by GDI+ for pretty much any problem, so isn't reliable as an actual indicator that you're out of memory. If // you really are out of memory, it's very likely you'll get another OOM shortly. ActionPanel.ShowError(string.Format(SR.DesignerActionPanel_ErrorInvokingAction, _methodItem!.DisplayName, Environment.NewLine + ex.Message)); } finally { ActionPanel.InMethodInvoke = false; } } internal override void UpdateActionItem(LineInfo lineInfo, ToolTip toolTip, ref int currentTabIndex) { Info info = (Info)lineInfo; _actionList = info.List; _methodItem = info.Item; toolTip.SetToolTip(_linkLabel, _methodItem.Description); _linkLabel.Text = StripAmpersands(_methodItem.DisplayName); _linkLabel.AccessibleDescription = _methodItem.Description; _linkLabel.TabIndex = currentTabIndex++; } private sealed class MethodItemLinkLabel : LinkLabel { protected override bool ProcessDialogKey(Keys keyData) { if ((keyData & Keys.Control) == Keys.Control) { Keys keyCode = keyData & Keys.KeyCode; switch (keyCode) { case Keys.Tab: // We specifically ignore Ctrl+Tab because it prevents the window switcher dialog // from showing up in VS. Normally the key combination is only needed // when a LinkLabel contains multiple links, but that can't happen // inside the DesignerActionPanel. return false; } } return base.ProcessDialogKey(keyData); } } public static StandardLineInfo CreateLineInfo(DesignerActionList list, DesignerActionMethodItem item) => new Info(list, item); private sealed class Info(DesignerActionList list, DesignerActionMethodItem item) : StandardLineInfo(list) { public override DesignerActionMethodItem Item { get; } = item; public override Line CreateLine(IServiceProvider serviceProvider, DesignerActionPanel actionPanel) { return new MethodLine(serviceProvider, actionPanel); } public override Type LineType => typeof(MethodLine); } } }