RichTextBox切换Resize模式后仅首次生效,ContentsResized事件不再触发
问题:RichTextBox切换适配模式后ContentsResized事件失效
在Windows Forms应用中使用名为rtbEditor的RichTextBox,勾选复选框ckbResize时希望通过监听ContentsResized事件让控件根据内容自动调整大小,预期行为:
- 勾选
ckbResize时,RichTextBox适配内容尺寸; - 取消勾选时,RichTextBox占满窗体大小;
- 再次勾选
ckbResize后,仍能随内容变化自动调整。
但实际仅首次勾选有效,取消后再勾选,自动调整失效,ContentsResized事件不再触发。现有代码如下:
private void rtbEditor_ContentsResized(object sender, ContentsResizedEventArgs e) { if (ckbResize.Checked) { rtbEditor.Height = e.NewRectangle.Height; rtbEditor.Width = e.NewRectangle.Width + 1; rtbEditor.Left = this.ClientSize.Width - rtbEditor.Width; } else { rtbEditor.Width = this.ClientSize.Width; rtbEditor.Height = this.ClientSize.Height; rtbEditor.Left = 0; } } private void ckbResize_CheckedChanged(object sender, EventArgs e) { if (ckbResize.Checked) { // Force initial resize rtbEditor.Rtf = rtbEditor.Rtf; } else { rtbEditor.Width = this.ClientSize.Width; rtbEditor.Height = this.ClientSize.Height; rtbEditor.Left = 0; } }
即使重置RTF内容或调用Invalidate(),重新启用复选框后ContentsResized事件仍不触发。
解决方案
问题根源在于当RichTextBox被设置为占满窗体时,控件内部尺寸计算逻辑被干扰,导致后续内容变化无法触发ContentsResized事件。以下是两种简洁修复方案:
方案一:手动计算内容尺寸并强制刷新
修改ckbResize_CheckedChanged方法,主动计算内容所需尺寸并设置,同时强制控件刷新以恢复事件响应:
private void ckbResize_CheckedChanged(object sender, EventArgs e) { if (ckbResize.Checked) { // 手动计算内容实际占用尺寸(包含边距) using (Graphics g = rtbEditor.CreateGraphics()) { SizeF contentSize = g.MeasureString(rtbEditor.Text, rtbEditor.Font, int.MaxValue, StringFormat.GenericTypographic); int targetWidth = (int)Math.Ceiling(contentSize.Width) + 20; // 预留控件边距 int targetHeight = (int)Math.Ceiling(contentSize.Height) + 20; rtbEditor.Width = targetWidth; rtbEditor.Height = targetHeight; rtbEditor.Left = this.ClientSize.Width - rtbEditor.Width; } // 强制控件重新布局,确保后续内容变化能触发ContentsResized rtbEditor.PerformLayout(); } else { rtbEditor.Width = this.ClientSize.Width; rtbEditor.Height = this.ClientSize.Height; rtbEditor.Left = 0; } }
同时简化ContentsResized事件处理,避免不必要的逻辑:
private void rtbEditor_ContentsResized(object sender, ContentsResizedEventArgs e) { if (!ckbResize.Checked) return; rtbEditor.Height = e.NewRectangle.Height; rtbEditor.Width = e.NewRectangle.Width + 1; rtbEditor.Left = this.ClientSize.Width - rtbEditor.Width; }
方案二:利用AutoSize属性重置触发逻辑
通过切换AutoSize属性并临时修改内容,强制触发ContentsResized事件:
private void ckbResize_CheckedChanged(object sender, EventArgs e) { if (ckbResize.Checked) { rtbEditor.AutoSize = true; // 临时修改内容再恢复,强制触发ContentsResized事件 string originalText = rtbEditor.Text; rtbEditor.Text = " "; rtbEditor.Text = originalText; } else { rtbEditor.AutoSize = false; rtbEditor.Width = this.ClientSize.Width; rtbEditor.Height = this.ClientSize.Height; rtbEditor.Left = 0; } }
该方案依赖控件自身的AutoSize特性,代码更简洁,适合内容格式相对简单的场景。
内容的提问来源于stack exchange,提问作者Food plus
相关产品推荐
相关产品推荐

