窗体Controls的OfType<>方法的使用

本文介绍了一种在Visual Studio中批量清空窗体上所有TextBox控件的方法,适用于VS2008及以上的版本,同时也提供了VS2005中实现相同功能的替代方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  如果当前窗体中有大量TextBox对象,需要将所有对象的输入内容清空而又不想在代码中逐个设置Text属性,可以考虑使用OfType<>方法,用法:

           IEnumerable<TextBox> textBoxes = this.Controls.OfType<TextBox>(); //所有同类型控件
            foreach (TextBox textBox in textBoxes)//执行相同操作
                textBox.Text = "";

显然,对于任类的对象均可考虑此方法,不单单适用于TextBox类
以上方法在VS 2008中可用

VS2005里没封装那个方法,可以通过以下方法实现相同功能:
foreach (Control textBox in this.Controls)
            {
                if (textBox.GetType().Name == "TextBox")//或者textBox.GetType().FullName == "System.Windows.Forms.TextBox"
                    textBox.Text = "";
            }
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.IO; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Newtonsoft.Json; // 需通过NuGet安装:Install-Package Newtonsoft.Json namespace Vision.Controls { #region 基础类型定义 public enum PortType { Input, Output } public enum NodeStatus { Idle, Executing, Success, Error, Paused } public class Port { public string Name { get; set; } public PortType Type { get; set; } public Point Position { get; set; } // 相对于节点的偏移 public Port ConnectedPort { get; set; } // 连接的目标端口 public VisionNode Parent { get; set; } // 所属节点 } public class Connection { public Port StartPort { get; set; } public Port EndPort { get; set; } public Point StartPosition { get; set; } // 临时连接起点(绘制用) public Point EndPosition { get; set; } // 临时连接终点(绘制用) } public class ExecutionEventArgs : EventArgs { public object Output { get; set; } public Exception Error { get; set; } } public interface IExecutable { string UniqueId { get; } NodeStatus Status { get; } IDictionary<string, object> Parameters { get; set; } object Execute(IDictionary<string, object> inputs); Task<object> ExecuteAsync(IDictionary<string, object> inputs, CancellationToken ct); event EventHandler<ExecutionEventArgs> ExecutionCompleted; } #endregion #region 节点控件(VisionNode) public partial class VisionNode : UserControl, IExecutable { public string Title { get; set; } = "Node"; public List<Port> InputPorts { get; } = new List<Port>(); public List<Port> OutputPorts { get; } = new List<Port>(); public string UniqueId { get; } = Guid.NewGuid().ToString(); public NodeStatus Status { get; private set; } = NodeStatus.Idle; public IDictionary<string, object> Parameters { get; set; } = new Dictionary<string, object>(); public bool IsSelected { get; set; } public event EventHandler<ExecutionEventArgs> ExecutionCompleted; public VisionNode() { DoubleBuffered = true; Size = new Size(200, 100); // 初始化端口(左侧输入,右侧输出) InputPorts.Add(new Port { Name = "In1", Type = PortType.Input, Position = new Point(10, 30), Parent = this }); InputPorts.Add(new Port { Name = "In2", Type = PortType.Input, Position = new Point(10, 60), Parent = this }); OutputPorts.Add(new Port { Name = "Out1", Type = PortType.Output, Position = new Point(180, 30), Parent = this }); OutputPorts.Add(new Port { Name = "Out2", Type = PortType.Output, Position = new Point(180, 60), Parent = this }); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); // 绘制节点边框(状态色) using (var pen = new Pen(GetStatusColor(), 2)) { e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1); } // 绘制标题 e.Graphics.DrawString(Title, Font, Brushes.Black, new PointF(10, 10)); // 绘制端口(圆形) foreach (var port in InputPorts.Concat(OutputPorts)) { var portCenter = new Point(port.Position.X + 5, port.Position.Y + 5); e.Graphics.FillEllipse(Brushes.Gray, portCenter.X - 5, portCenter.Y - 5, 10, 10); } // 绘制选中框 if (IsSelected) { using (var pen = new Pen(Color.Blue, 2) { DashStyle = DashStyle.Dash }) { e.Graphics.DrawRectangle(pen, 0, 0, Width - 1, Height - 1); } } } private Color GetStatusColor() { return Status switch { NodeStatus.Executing => Color.Orange, NodeStatus.Success => Color.Green, NodeStatus.Error => Color.Red, NodeStatus.Paused => Color.Yellow, _ => Color.Gray }; } public virtual object Execute(IDictionary<string, object> inputs) { Status = NodeStatus.Executing; try { Thread.Sleep(1000); // 模拟业务逻辑 var output = new { Timestamp = DateTime.Now }; Status = NodeStatus.Success; ExecutionCompleted?.Invoke(this, new ExecutionEventArgs { Output = output }); return output; } catch (Exception ex) { Status = NodeStatus.Error; ExecutionCompleted?.Invoke(this, new ExecutionEventArgs { Error = ex }); return null; } finally { Invalidate(); } } public virtual async Task<object> ExecuteAsync(IDictionary<string, object> inputs, CancellationToken ct) { Status = NodeStatus.Executing; try { await Task.Delay(1500, ct); // 模拟异步操作 var output = new { Result = "Async Success" }; Status = NodeStatus.Success; ExecutionCompleted?.Invoke(this, new ExecutionEventArgs { Output = output }); return output; } catch (OperationCanceledException) { Status = NodeStatus.Paused; ExecutionCompleted?.Invoke(this, new ExecutionEventArgs { Error = new OperationCanceledException() }); return null; } catch (Exception ex) { Status = NodeStatus.Error; ExecutionCompleted?.Invoke(this, new ExecutionEventArgs { Error = ex }); return null; } finally { Invalidate(); } } } #endregion #region 流程画布(WorkflowCanvas) public partial class WorkflowCanvas : Panel { public List<VisionNode> Nodes { get; } = new List<VisionNode>(); public List<Connection> Connections { get; } = new List<Connection>(); // 交互状态 private VisionNode _draggingNode; private Point _dragStart; private Port _draggingPort; private Connection _tempConnection; private Rectangle _selectionRect; private bool _isSelecting; private float _scale = 1.0f; // 命令历史 private Stack<ICommand> _undoStack = new Stack<ICommand>(); private Stack<ICommand> _redoStack = new Stack<ICommand>(); public WorkflowCanvas() { DoubleBuffered = true; MouseDown += OnMouseDown; MouseMove += OnMouseMove; MouseUp += OnMouseUp; MouseWheel += OnMouseWheel; } public void AddNode(VisionNode node) { Nodes.Add(node); Controls.Add(node); Invalidate(); } public void RemoveNode(VisionNode node) { var connectionsToRemove = Connections.Where(c => c.StartPort.Parent == node || c.EndPort.Parent == node).ToList(); foreach (var conn in connectionsToRemove) Connections.Remove(conn); Nodes.Remove(node); Controls.Remove(node); Invalidate(); } #region 鼠标交互处理 private void OnMouseDown(object sender, MouseEventArgs e) { var scaledPoint = new Point((int)(e.X / _scale), (int)(e.Y / _scale)); _draggingNode = Nodes.FirstOrDefault(n => n.Bounds.Contains(scaledPoint)); if (_draggingNode != null) { _dragStart = scaledPoint; _draggingPort = CheckPortClick(_draggingNode, scaledPoint); if (_draggingPort != null) { _tempConnection = new Connection { StartPort = _draggingPort, StartPosition = new Point( _draggingNode.Location.X + _draggingPort.Position.X + 5, _draggingNode.Location.Y + _draggingPort.Position.Y + 5) }; } } else if (e.Button == MouseButtons.Left) { _isSelecting = true; _selectionRect = new Rectangle(scaledPoint, Size.Empty); } } private Port CheckPortClick(VisionNode node, Point localPoint) { foreach (var port in node.InputPorts.Concat(node.OutputPorts)) { var portCenter = new Point(port.Position.X + 5, port.Position.Y + 5); if (Math.Sqrt(Math.Pow(localPoint.X - portCenter.X, 2) + Math.Pow(localPoint.Y - portCenter.Y, 2)) <= 5) return port; } return null; } private void OnMouseMove(object sender, MouseEventArgs e) { var scaledPoint = new Point((int)(e.X / _scale), (int)(e.Y / _scale)); if (_draggingNode != null && _draggingPort == null) { int dx = scaledPoint.X - _dragStart.X; int dy = scaledPoint.Y - _dragStart.Y; _draggingNode.Location = new Point(_draggingNode.Location.X + dx, _draggingNode.Location.Y + dy); _dragStart = scaledPoint; Invalidate(); } else if (_tempConnection != null) { _tempConnection.EndPosition = new Point((int)(e.X / _scale), (int)(e.Y / _scale)); Invalidate(); } else if (_isSelecting) { _selectionRect.Width = scaledPoint.X - _selectionRect.X; _selectionRect.Height = scaledPoint.Y - _selectionRect.Y; Invalidate(); } } private void OnMouseUp(object sender, MouseEventArgs e) { var scaledPoint = new Point((int)(e.X / _scale), (int)(e.Y / _scale)); if (_tempConnection != null) { var targetNode = Nodes.FirstOrDefault(n => n.Bounds.Contains(scaledPoint)); var targetPort = targetNode != null ? CheckPortClick(targetNode, scaledPoint) : null; if (targetPort != null && _tempConnection.StartPort.Type != targetPort.Type) { _tempConnection.EndPort = targetPort; Connections.Add(_tempConnection); _tempConnection.StartPort.ConnectedPort = targetPort; targetPort.ConnectedPort = _tempConnection.StartPort; } _tempConnection = null; _draggingPort = null; } else if (_isSelecting) { _isSelecting = false; foreach (var node in Nodes) node.IsSelected = _selectionRect.IntersectsWith(node.Bounds); } _draggingNode = null; Invalidate(); } private void OnMouseWheel(object sender, MouseEventArgs e) { if (ModifierKeys == Keys.Control) { _scale = Math.Max(0.1f, Math.Min(5.0f, _scale * (e.Delta > 0 ? 1.1f : 0.9f))); Invalidate(); } } #endregion #region 绘制逻辑 protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.ScaleTransform(_scale, _scale); // 绘制节点 foreach (var node in Nodes) e.Graphics.DrawImageUnscaled(node.BackgroundImage, node.Location); // 绘制连线(贝塞尔曲线) foreach (var conn in Connections) { Point start = conn.StartPort != null ? new Point(conn.StartPort.Parent.Location.X + conn.StartPort.Position.X + 5, conn.StartPort.Parent.Location.Y + conn.StartPort.Position.Y + 5) : conn.StartPosition; Point end = conn.EndPort != null ? new Point(conn.EndPort.Parent.Location.X + conn.EndPort.Position.X + 5, conn.EndPort.Parent.Location.Y + conn.EndPort.Position.Y + 5) : conn.EndPosition; Point ctrl1 = new Point((start.X + end.X) / 2, start.Y - 50); Point ctrl2 = new Point((start.X + end.X) / 2, end.Y + 50); e.Graphics.DrawBezier(Pens.Black, start, ctrl1, ctrl2, end); } // 绘制临时连接 if (_tempConnection != null) { using (var pen = new Pen(Color.Red, 1) { DashStyle = DashStyle.Dash }) { e.Graphics.DrawLine(pen, _tempConnection.StartPosition, _tempConnection.EndPosition); } } // 绘制框选区域 if (_isSelecting) { using (var pen = new Pen(Color.Blue, 1) { DashStyle = DashStyle.Dash }) { e.Graphics.DrawRectangle(pen, _selectionRect); } } e.Graphics.ResetTransform(); } #endregion #region 序列化与反序列化 public string Serialize() { var data = new { Nodes = Nodes.Select(n => new { Title = n.Title, Location = n.Location, InputPorts = n.InputPorts.Select(p => new { p.Name, p.Type, p.Position }), OutputPorts = n.OutputPorts.Select(p => new { p.Name, p.Type, p.Position }), Parameters = n.Parameters, IsSelected = n.IsSelected }).ToList(), Connections = Connections.Select(c => new { StartPort = c.StartPort != null ? new { c.StartPort.Parent.Title, c.StartPort.Name, c.StartPort.Type } : null, EndPort = c.EndPort != null ? new { c.EndPort.Parent.Title, c.EndPort.Name, c.EndPort.Type } : null, StartPosition = c.StartPosition, EndPosition = c.EndPosition }).ToList(), Scale = _scale }; return JsonConvert.SerializeObject(data, Formatting.Indented); } public void Deserialize(string json) { var data = JsonConvert.DeserializeAnonymousType(json, new { Nodes = new List<NodeDTO>(), Connections = new List<ConnectionDTO>(), Scale = 1.0f }); Nodes.Clear(); Connections.Clear(); Controls.Clear(); _scale = data.Scale; var nodeMap = new Dictionary<string, VisionNode>(); foreach (var nodeDTO in data.Nodes) { var node = new VisionNode { Title = nodeDTO.Title, Location = nodeDTO.Location, IsSelected = nodeDTO.IsSelected }; node.Parameters = nodeDTO.Parameters.ToDictionary(k => k.Key, v => v.Value); node.InputPorts.Clear(); node.InputPorts.AddRange(nodeDTO.InputPorts.Select(p => new Port { Name = p.Name, Type = p.Type, Position = p.Position, Parent = node })); node.OutputPorts.Clear(); node.OutputPorts.AddRange(nodeDTO.OutputPorts.Select(p => new Port { Name = p.Name, Type = p.Type, Position = p.Position, Parent = node })); AddNode(node); nodeMap[node.Title] = node; } foreach (var connDTO in data.Connections) { if (connDTO.StartPort == null || connDTO.EndPort == null) continue; if (!nodeMap.TryGetValue(connDTO.StartPort.Title, out var startNode) || !nodeMap.TryGetValue(connDTO.EndPort.Title, out var endNode)) continue; var startPort = startNode.InputPorts.Concat(startNode.OutputPorts) .First(p => p.Name == connDTO.StartPort.Name && p.Type == connDTO.StartPort.Type); var endPort = endNode.InputPorts.Concat(endNode.OutputPorts) .First(p => p.Name == connDTO.EndPort.Name && p.Type == connDTO.EndPort.Type); var connection = new Connection { StartPort = startPort, EndPort = endPort, StartPosition = connDTO.StartPosition, EndPosition = connDTO.EndPosition }; Connections.Add(connection); startPort.ConnectedPort = endPort; endPort.ConnectedPort = startPort; } Invalidate(); } private class NodeDTO { public string Title { get; set; } public Point Location { get; set; } public List<PortDTO> InputPorts { get; set; } public List<PortDTO> OutputPorts { get; set; } public Dictionary<string, object> Parameters { get; set; } public bool IsSelected { get; set; } } private class PortDTO { public string Name { get; set; } public PortType Type { get; set; } public Point Position { get; set; } } private class ConnectionDTO { public PortRef StartPort { get; set; } public PortRef EndPort { get; set; } public Point StartPosition { get; set; } public Point EndPosition { get; set; } } private class PortRef { public string Title { get; set; } public string Name { get; set; } public PortType Type { get; set; } } #endregion #region 命令模式(撤销/重做) public interface ICommand { void Execute(); void Undo(); } public void ExecuteCommand(ICommand command) { command.Execute(); _undoStack.Push(command); _redoStack.Clear(); } public void Undo() { if (_undoStack.Count > 0) { var cmd = _undoStack.Pop(); cmd.Undo(); _redoStack.Push(cmd); Invalidate(); } } public void Redo() { if (_redoStack.Count > 0) { var cmd = _redoStack.Pop(); cmd.Execute(); _undoStack.Push(cmd); Invalidate(); } } public class AddNodeCommand : ICommand { private WorkflowCanvas _canvas; private VisionNode _node; public AddNodeCommand(WorkflowCanvas canvas, VisionNode node) { _canvas = canvas; _node = node; } public void Execute() => _canvas.AddNode(_node); public void Undo() => _canvas.RemoveNode(_node); } #endregion } #endregion #region 执行引擎(WorkflowRunner) public class WorkflowRunner { private WorkflowCanvas _canvas; private Dictionary<string, object> _dataCache = new Dictionary<string, object>(); private CancellationTokenSource _cts; public WorkflowRunner(WorkflowCanvas canvas) => _canvas = canvas; public async Task RunAsync() { _cts = new CancellationTokenSource(); var nodes = _canvas.Nodes.OfType<IExecutable>().ToList(); var dependencyGraph = BuildDependencyGraph(nodes); var sortedNodes = TopologicalSort(dependencyGraph); var tasks = sortedNodes.Select(node => Task.Run(async () => { var inputs = CollectInputs(node); var output = await node.ExecuteAsync(inputs, _cts.Token); _dataCache[node.UniqueId] = output; }, _cts.Token)); await Task.WhenAll(tasks); } private Dictionary<IExecutable, List<IExecutable>> BuildDependencyGraph(List<IExecutable> nodes) { var graph = new Dictionary<IExecutable, List<IExecutable>>(); foreach (var node in nodes) { graph[node] = new List<IExecutable>(); var visionNode = node as VisionNode; foreach (var port in visionNode.InputPorts) { if (port.ConnectedPort != null && port.ConnectedPort.Parent is IExecutable dependency) graph[dependency].Add(node); } } return graph; } private List<IExecutable> TopologicalSort(Dictionary<IExecutable, List<IExecutable>> graph) { var inDegree = graph.ToDictionary(k => k.Key, v => v.Value.Count); var queue = new Queue<IExecutable>(graph.Where(kv => kv.Value.Count == 0).Select(kv => kv.Key)); var result = new List<IExecutable>(); while (queue.Count > 0) { var node = queue.Dequeue(); result.Add(node); foreach (var neighbor in graph[node]) if (--inDegree[neighbor] == 0) queue.Enqueue(neighbor); } return result; } private IDictionary<string, object> CollectInputs(IExecutable node) { var inputs = new Dictionary<string, object>(); var visionNode = node as VisionNode; foreach (var port in visionNode.InputPorts) { if (port.ConnectedPort != null && port.ConnectedPort.Parent is IExecutable source && _dataCache.TryGetValue(source.UniqueId, out var data)) { inputs[port.Name] = data; } } return inputs; } public void Cancel() => _cts?.Cancel(); } #endregion #region 示例窗体(MainForm) static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } } public partial class MainForm : Form { private WorkflowCanvas _canvas; private WorkflowRunner _runner; public MainForm() { InitializeComponent(); _canvas = new WorkflowCanvas { Dock = DockStyle.Fill }; Controls.Add(_canvas); // 示例节点 var node1 = new VisionNode { Title = "Source", Location = new Point(100, 100) }; var node2 = new VisionNode { Title = "Processor", Location = new Point(300, 200) }; _canvas.AddNode(node1); _canvas.AddNode(node2); // 按钮区 var buttonPanel = new Panel { Dock = DockStyle.Top, Height = 40 }; Controls.Add(buttonPanel); var btnRun = new Button { Text = "Run Workflow", Location = new Point(10, 10) }; btnRun.Click += async (s, e) => { _runner = new WorkflowRunner(_canvas); await _runner.RunAsync(); }; buttonPanel.Controls.Add(btnRun); var btnSave = new Button { Text = "Save", Location = new Point(120, 10) }; btnSave.Click += (s, e) => File.WriteAllText("workflow.json", _canvas.Serialize()); buttonPanel.Controls.Add(btnSave); var btnLoad = new Button { Text = "Load", Location = new Point(190, 10) }; btnLoad.Click += (s, e) => _canvas.Deserialize(File.ReadAllText("workflow.json")); buttonPanel.Controls.Add(btnLoad); var btnUndo = new Button { Text = "Undo", Location = new Point(260, 10) }; btnUndo.Click += (s, e) => _canvas.Undo(); buttonPanel.Controls.Add(btnUndo); var btnRedo = new Button { Text = "Redo", Location = new Point(330, 10) }; btnRedo.Click += (s, e) => _canvas.Redo(); buttonPanel.Controls.Add(btnRedo); } private void InitializeComponent() { this.SuspendLayout(); this.ClientSize = new Size(800, 600); this.Text = "Workflow Editor"; this.ResumeLayout(false); } } #endregion } 优化
06-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值