ฉันมีกล่องข้อความที่มีคุณสมบัติ. Multiline ตั้งค่าเป็นจริง ในช่วงเวลาปกติฉันจะเพิ่มบรรทัดใหม่ให้กับข้อความ ฉันต้องการให้กล่องข้อความเลื่อนไปที่รายการล่างสุดโดยอัตโนมัติ (รายการที่ใหม่ที่สุด) ทุกครั้งที่มีการเพิ่มบรรทัดใหม่ ฉันจะทำสิ่งนี้ได้อย่างไร
ฉันมีกล่องข้อความที่มีคุณสมบัติ. Multiline ตั้งค่าเป็นจริง ในช่วงเวลาปกติฉันจะเพิ่มบรรทัดใหม่ให้กับข้อความ ฉันต้องการให้กล่องข้อความเลื่อนไปที่รายการล่างสุดโดยอัตโนมัติ (รายการที่ใหม่ที่สุด) ทุกครั้งที่มีการเพิ่มบรรทัดใหม่ ฉันจะทำสิ่งนี้ได้อย่างไร
คำตอบ:
ในช่วงเวลาปกติฉันจะเพิ่มบรรทัดใหม่ให้กับข้อความ ฉันต้องการให้กล่องข้อความเลื่อนไปที่รายการล่างสุดโดยอัตโนมัติ (รายการที่ใหม่ที่สุด) ทุกครั้งที่มีการเพิ่มบรรทัดใหม่
หากคุณใช้TextBox.AppendText(string text)
มันจะเลื่อนโดยอัตโนมัติไปที่ท้ายข้อความต่อท้ายใหม่ มันหลีกเลี่ยงแถบเลื่อนกะพริบถ้าคุณเรียกมันเป็นวง
นอกจากนี้ยังเป็นลำดับความสำคัญที่เร็วกว่าการต่อเข้ากับ.Text
คุณสมบัติ แม้ว่ามันจะขึ้นอยู่กับว่าคุณโทรหาบ่อยแค่ไหน ฉันกำลังทดสอบด้วยการวนรอบที่แน่นหนา
นี่จะไม่เลื่อนถ้ามันถูกเรียกก่อนที่จะมีการแสดงกล่องข้อความหรือถ้าไม่เห็นกล่องข้อความ (เช่นในแท็บอื่นของ TabPanel) ดูTextBox.AppendText () ไม่ต้องทำการตรวจสอบอัตโนมัติ สิ่งนี้อาจมีหรือไม่มีความสำคัญขึ้นอยู่กับว่าคุณต้องการใช้การเลื่อนอัตโนมัติเมื่อผู้ใช้ไม่เห็นกล่องข้อความหรือไม่
ดูเหมือนว่าวิธีการทางเลือกจากคำตอบอื่น ๆ ก็ไม่ได้ผลในกรณีนี้ วิธีหนึ่งในนั้นคือการเลื่อนเพิ่มเติมในVisibleChanged
เหตุการณ์:
textBox.VisibleChanged += (sender, e) =>
{
if (textBox.Visible)
{
textBox.SelectionStart = textBox.TextLength;
textBox.ScrollToCaret();
}
};
ภายในAppendText
ทำสิ่งนี้:
textBox.Select(textBox.TextLength + 1, 0);
textBox.SelectedText = textToAppend;
แต่ไม่มีเหตุผลที่จะทำด้วยตนเอง
(หากคุณถอดรหัสด้วยตัวคุณเองคุณจะเห็นว่ามันใช้วิธีการภายในที่มีประสิทธิภาพมากกว่าและมีสิ่งที่ดูเหมือนจะเป็นกรณีพิเศษเล็กน้อย)
tb.Text += ....
และ WndProc และ marshals ตอนนี้ฉันรู้สึกโง่: D
คุณสามารถใช้ข้อมูลโค้ดต่อไปนี้:
myTextBox.SelectionStart = myTextBox.Text.Length;
myTextBox.ScrollToCaret();
ซึ่งจะเลื่อนไปยังจุดสิ้นสุดโดยอัตโนมัติ
ดูเหมือนว่าอินเทอร์เฟซที่มีการเปลี่ยนแปลงใน. NET 4.0 มีวิธีการดังต่อไปนี้ที่บรรลุทั้งหมดข้างต้น ตามที่ Tommy Engebretsen แนะนำให้วางไว้ในตัวจัดการเหตุการณ์ TextChanged ทำให้เป็นอัตโนมัติ
textBox1.ScrollToEnd();
TextBoxBase
คลาสในSystem.Windows.Controls.Primitives
namespace ( PresentationFramework
แอสเซมบลี WPF) วิธีนี้ไม่มีอยู่และจะไม่ทำงานใน WinForms ซึ่งTextBox
คลาสจะสืบทอดมาจากTextBoxBase
ในSystem.Windows.Forms
เนมสเปซ ( System.Windows.Forms
ชุดประกอบ, WinForms)
ScrollToEnd()
อาจมีประสิทธิภาพต่ำมาก ในแอพของฉันคิดเป็นกว่า 50% ของเวลาการทำโปรไฟล์
ลองเพิ่มรหัสที่แนะนำไปยังเหตุการณ์ TextChanged:
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
}
textBox1.Focus()
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
ไม่ได้ผลสำหรับฉัน (Windows 8.1 ไม่ว่าด้วยเหตุผลใด)
และเนื่องจากฉันยังอยู่ใน. NET 2.0 ฉันไม่สามารถใช้ ScrollToEnd
แต่งานนี้:
public class Utils
{
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(System.IntPtr hWnd, int wMsg, System.IntPtr wParam, System.IntPtr lParam);
private const int WM_VSCROLL = 0x115;
private const int SB_BOTTOM = 7;
/// <summary>
/// Scrolls the vertical scroll bar of a multi-line text box to the bottom.
/// </summary>
/// <param name="tb">The text box to scroll</param>
public static void ScrollToBottom(System.Windows.Forms.TextBox tb)
{
if(System.Environment.OSVersion.Platform != System.PlatformID.Unix)
SendMessage(tb.Handle, WM_VSCROLL, new System.IntPtr(SB_BOTTOM), System.IntPtr.Zero);
}
}
VB.NET:
Public Class Utils
<System.Runtime.InteropServices.DllImport("user32.dll", CharSet := System.Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function SendMessage(hWnd As System.IntPtr, wMsg As Integer, wParam As System.IntPtr, lParam As System.IntPtr) As Integer
End Function
Private Const WM_VSCROLL As Integer = &H115
Private Const SB_BOTTOM As Integer = 7
''' <summary>
''' Scrolls the vertical scroll bar of a multi-line text box to the bottom.
''' </summary>
''' <param name="tb">The text box to scroll</param>
Public Shared Sub ScrollToBottom(tb As System.Windows.Forms.TextBox)
If System.Environment.OSVersion.Platform <> System.PlatformID.Unix Then
SendMessage(tb.Handle, WM_VSCROLL, New System.IntPtr(SB_BOTTOM), System.IntPtr.Zero)
End If
End Sub
End Class
ฉันต้องการเพิ่มการรีเฟรช:
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();
ฉันพบความแตกต่างง่ายๆที่ยังไม่ได้รับการแก้ไขในหัวข้อนี้
หากคุณกำลังScrollToCarat()
โทรทั้งหมดเป็นส่วนหนึ่งของLoad()
กิจกรรมในแบบฟอร์มของคุณมันจะไม่ทำงาน ฉันเพิ่งเพิ่มการScrollToCarat()
เรียกของฉันไปยังActivated()
กิจกรรมของแบบฟอร์มและทำงานได้ดี
แก้ไข
สิ่งสำคัญคือการเลื่อนนี้เฉพาะเมื่อActivated
เหตุการณ์ของฟอร์มครั้งแรกถูกไล่ออก (ไม่ใช่ในการเปิดใช้งานในภายหลัง) หรือจะเลื่อนทุกครั้งที่เปิดใช้งานฟอร์มซึ่งเป็นสิ่งที่คุณไม่ต้องการ
ดังนั้นหากคุณเพียงวางActivated()
เหตุการณ์เพื่อเลื่อนข้อความของคุณเมื่อโปรแกรมของคุณโหลดคุณสามารถยกเลิกการสมัครรับกิจกรรมภายในตัวจัดการเหตุการณ์เองได้ดังนั้น:
Activated -= new System.EventHandler(this.Form1_Activated);
หากคุณมีสิ่งอื่น ๆ ที่คุณต้องทำในแต่ละครั้งที่เปิดใช้งานแบบฟอร์มของคุณคุณสามารถตั้งค่าเป็นbool
จริงในครั้งแรกที่Activated()
เหตุการณ์ของคุณถูกไล่ออกดังนั้นคุณจะไม่เลื่อนไปที่การเปิดใช้งานในภายหลัง แต่ยังสามารถทำสิ่งอื่น ๆ ทำ.
นอกจากนี้ถ้าคุณTextBox
อยู่บนแท็บที่ไม่ได้SelectedTab
, ScrollToCarat()
จะไม่มีผลกระทบ อย่างน้อยคุณต้องทำให้แท็บที่เลือกไว้ขณะเลื่อน คุณสามารถใส่รหัสในYourTab.SuspendLayout();
และYourTab.ResumeLayout(false);
จับคู่หากแบบฟอร์มของคุณกะพริบเมื่อคุณทำเช่นนี้
สิ้นสุดการแก้ไข
หวังว่านี่จะช่วยได้!
สิ่งนี้จะเลื่อนไปที่ส่วนท้ายของกล่องข้อความเมื่อมีการเปลี่ยนแปลงข้อความ แต่ยังอนุญาตให้ผู้ใช้เลื่อนขึ้น
outbox.SelectionStart = outbox.Text.Length;
outbox.ScrollToEnd();
ทดสอบใน Visual Studio Enterprise 2017
สำหรับผู้อื่นที่มาถึงที่นี่คาดว่าจะเห็นการใช้งานเว็บฟอร์มคุณต้องการใช้เครื่องมือจัดการเหตุการณ์ endRequest ของตัวจัดการหน้า ( https://stackoverflow.com/a/1388170/1830512 ) นี่คือสิ่งที่ฉันทำกับกล่องข้อความของฉันในหน้าเนื้อหาจากหน้าต้นแบบโปรดเพิกเฉยต่อความจริงที่ว่าฉันไม่ได้ใช้ตัวแปรสำหรับการควบคุม:
var prm = Sys.WebForms.PageRequestManager.getInstance();
function EndRequestHandler() {
if ($get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>') != null) {
$get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>').scrollTop =
$get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>').scrollHeight;
}
}
prm.add_endRequest(EndRequestHandler);
สิ่งนี้ใช้ได้สำหรับฉันเท่านั้น ...
txtSerialLogging-> Text = "";
txtSerialLogging-> appendText (s);
ฉันลองทุกกรณีข้างต้น แต่ปัญหาคือในกรณีของข้อความของฉันสามารถลดเพิ่มและยังสามารถคงที่เป็นเวลานาน static หมายถึง static length (lines) แต่เนื้อหานั้นแตกต่างกัน
ดังนั้นฉันกำลังเผชิญหน้ากับสถานการณ์การกระโดดหนึ่งบรรทัดในตอนท้ายเมื่อความยาว (เส้น) ยังคงเหมือนเดิมในบางครั้ง ...
ฉันใช้ฟังก์ชั่นนี้:
private void Log (string s) {
TB1.AppendText(Environment.NewLine + s);
TB1.ScrollToCaret();
}