| File: System\Windows\Forms\DataBinding\Command.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Windows.Forms; internal class Command : WeakReference { private static Command?[]? s_cmds; private static int s_icmdTry; private static readonly Lock s_internalSyncObject = new(); private const int IdMin = 0x00100; private const int IdLim = 0x10000; internal int _id; public Command(ICommandExecutor target) : base(target, false) { AssignID(this); } public virtual int ID => _id; protected static void AssignID(Command cmd) { lock (s_internalSyncObject) { int icmd; if (s_cmds is null) { s_cmds = new Command[20]; icmd = 0; } else { Debug.Assert(s_cmds.Length > 0, "why is cmds.Length zero?"); Debug.Assert(s_icmdTry >= 0, "why is icmdTry negative?"); int icmdLim = s_cmds.Length; if (s_icmdTry >= icmdLim) { s_icmdTry = 0; } // First look for an empty slot (starting at icmdTry). for (icmd = s_icmdTry; icmd < icmdLim; icmd++) { if (s_cmds[icmd] is null) { goto FindSlotComplete; } } for (icmd = 0; icmd < s_icmdTry; icmd++) { if (s_cmds[icmd] is null) { goto FindSlotComplete; } } // All slots have Command objects in them. Look for a command // with a null referent. for (icmd = 0; icmd < icmdLim; icmd++) { if (s_cmds[icmd]!.Target is null) { goto FindSlotComplete; } } // Grow the array. icmd = s_cmds.Length; icmdLim = Math.Min(IdLim - IdMin, 2 * icmd); if (icmdLim <= icmd) { // Already at maximal size. Do a garbage collect and look again. GC.Collect(); for (icmd = 0; icmd < icmdLim; icmd++) { if (s_cmds[icmd] is null || s_cmds[icmd]!.Target is null) { goto FindSlotComplete; } } throw new ArgumentException(SR.CommandIdNotAllocated); } else { Command[] newCmds = new Command[icmdLim]; Array.Copy(s_cmds, 0, newCmds, 0, icmd); s_cmds = newCmds; } } FindSlotComplete: cmd._id = icmd + IdMin; Debug.Assert(cmd._id is >= IdMin and < IdLim, "generated command id out of range"); s_cmds[icmd] = cmd; s_icmdTry = icmd + 1; } } public static bool DispatchID(int id) { Command? cmd = GetCommandFromID(id); if (cmd is null) { return false; } return cmd.Invoke(); } protected static void Dispose(Command cmd) { lock (s_internalSyncObject) { if (cmd._id >= IdMin) { cmd.Target = null; if (s_cmds![cmd._id - IdMin] == cmd) { s_cmds[cmd._id - IdMin] = null; } cmd._id = 0; } } } public virtual void Dispose() { if (_id >= IdMin) { Dispose(this); } } public static Command? GetCommandFromID(int id) { lock (s_internalSyncObject) { if (s_cmds is null) { return null; } int i = id - IdMin; if (i < 0 || i >= s_cmds.Length) { return null; } return s_cmds[i]; } } public virtual bool Invoke() { object? target = Target; if (target is not ICommandExecutor executor) { return false; } executor.Execute(); return true; } }