文号
t75231
阅读
19228
回复
22
收藏
2
C# 获取和设置TextBox等控件的滚动条位置
2015/11/07
IP:山东
由于TextBox修改Text后会导致鼠标光标位置和滚动条的改变
C#的textbox好像又没有获取与设置滚动条位置的函数,所以找到了俩设置的API

       [DllImport("user32.dll")]
        static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
hwnd:指定控件的句柄。
nBar:指定类型的滚动条。0:水平滚动条,1:垂直滚动条。
bRedraw: 重绘标志


        [DllImport("user32.dll", EntryPoint = "GetScrollPos")]
        public static extern int GetScrollPos( int hwnd, int nBar);
hwnd:指定控件的句柄。
nBar:指定类型的滚动条。0:水平滚动条,1:垂直滚动条。
return: 滚动条位置



The following example:


            MessageBox.Show(GetScrollPos((int)textBox1.Handle,1).ToString());
            SetScrollPos(textBox1.Handle, 1, textBox1.Lines.Length - 1, true);





修改TextBox的Text属性之后 恢复光标位置和滚动条位置

        private void button1_Click(object sender, EventArgs e)
        {
            int TextBoxSouSelectionStart = textBox1.SelectionStart;//TextBoxSou光标位置    
            int TextBoxSouSelectionLength = textBox1.SelectionLength;//TextBoxSou选中长度    
            int TextBoxSouScrollPos = GetScrollPos((int)textBox1.Handle,1);//TextBox滚动条位置


            textBox1.Text += "asdi";
            textBox1.Focus();


            textBox1.SelectionStart = TextBoxSouSelectionStart;
            textBox1.SelectionLength = TextBoxSouSelectionLength;
            SetScrollPos(textBox1.Handle, 1, TextBoxSouScrollPos, true);
            SendMessage(textBox1.Handle, 0x00B6, 0,TextBoxSouScrollPos);
        }
11年1个月前IP:四川
796048
1楼
这个特性确实有点麻烦→_→主要原因是光标位置发生改变了。
引用
评论
张静茹作者
11年1个月前IP:山东
796052
2楼
引用 acmilan:
这个特性确实有点麻烦→_→主要原因是光标位置发生改变了。
恩 mfc也这样吗?我现在用这个办法,能解决问题 但是还是会闪一下,有个文字被全选然后 取消全选的过程
引用
评论
11年1个月前IP:四川
796074
3楼
引用 张静茹:
恩 mfc也这样吗?我现在用这个办法,能解决问题 但是还是会闪一下,有个文字被全选然后 取消全选的过程
可能.NET的Text属性的实现有问题,建议尝试一下不改变Text属性,而是直接调用SetWindowText或者发送WM_SETTEXT设置文本。
引用
评论
张静茹作者
11年1个月前IP:山东
796078
4楼
引用 acmilan:
可能.NET的Text属性的实现有问题,建议尝试一下不改变Text属性,而是直接调用SetWindowText或者发送WM_SETTEXT设置文本。



TextBox继承自ConTrol
// System.Windows.Forms.TextBox
public override string Text
{
    get
    {
        return base.Text;
    }
    set
    {
        base.Text = value;
        this.selectionSet = false;
    }
}


ConTrol的
// System.Windows.Forms.Control
[Bindable(true), Localizable(true), DispId(-517), SRCategory("CatAppearance"), SRDescription("ControlTextDescr")]
public virtual string Text
{
    get
    {
        if (!this.CacheTextInternal)
        {
            return this.WindowText;
        }
        if (this.text != null)
        {
            return this.text;
        }
        return "";
    }
    set
    {
        if (value == null)
        {
            value = "";
        }
        if (value == this.Text)
        {
            return;
        }
        if (this.CacheTextInternal)
        {
            this.text = value;
        }
        this.WindowText = value;
        this.OnTextChanged(EventArgs.Empty);
        if (this.IsMnemonicsListenerAxSourced)
        {
            for (Control control = this; control != null; control = control.ParentInternal)
            {
                Control.ActiveXImpl activeXImpl = (Control.ActiveXImpl)control.Properties.GetObject(Control.PropActiveXImpl);
                if (activeXImpl != null)
                {
                    activeXImpl.UpdateAccelTable();
                    return;
                }
            }
        }
    }
}
引用
评论
11年1个月前IP:四川
796081
5楼
引用 张静茹:
TextBox继承自ConTrol
// System.Windows.Forms.TextBox
public override string Text
{
    get
    {
        return base....
this.selectionSet = false;
可能就是这一句出毛病的→_→
引用
评论
11年1个月前IP:四川
796083
6楼
mfc的CEditView实现了查找和替换功能,mfc的完整源代码可在vc/atlmfc/src找到。
引用
评论
张静茹作者
11年1个月前IP:山东
796086
7楼
引用 acmilan:
mfc的CEditView实现了查找和替换功能,mfc的完整源代码可在vc/atlmfc/src找到。
我自己声明一个类然后继承TextBox,然后自己重写Text属性set方法里写base.base.text = value;?
引用
评论
张静茹作者
11年1个月前IP:山东
796089
8楼
引用 张静茹:
我自己声明一个类然后继承TextBox,然后自己重写Text属性set方法里写base.base.text = value;?
[s::L] 没有base.base这种用法
引用
评论
张静茹作者
11年1个月前IP:山东
796092
9楼
引用 acmilan:
mfc的CEditView实现了查找和替换功能,mfc的完整源代码可在vc/atlmfc/src找到。

只用SetWindowText改变Text还是会自动把光标设置为0 滚动条在最上面,使用你的SetWindowText和我原来办法就完美了~~~
        [DllImport("user32.dll", EntryPoint = "SetWindowText", CharSet = CharSet.Ansi)]
        public static extern int SetWindowText(int hwnd, string lpString);
private void button1_Click(object sender, EventArgs e)
{
    int TextBoxSouSelectionStart = textBox1.SelectionStart;//TextBoxSou光标位置    
    int TextBoxSouSelectionLength = textBox1.SelectionLength;//TextBoxSou选中长度  
    int TextBoxSouScrollPos = GetScrollPos((int)textBox1.Handle, 1);//TextBox滚动条位置 
  
    SetWindowText((int)textBox1.Handle, textBox1.Text + "\r\n" + (Convert.ToUInt32(textBox1.Lines[textBox1.Lines.Length - 1]) + 1));
    textBox1.Focus();
  
    textBox1.SelectionStart = TextBoxSouSelectionStart;
    textBox1.SelectionLength = TextBoxSouSelectionLength;
    SetScrollPos(textBox1.Handle, 1, TextBoxSouScrollPos, true);
    SendMessage(textBox1.Handle, 0x00B6, 0, TextBoxSouScrollPos);
}
引用
评论
11年1个月前修改于 11年1个月前IP:四川
796101
10楼
引用 张静茹:
没有base.base这种用法
c++中调用基类的基类的函数是常见语法(Control::setText)
引用
评论
11年1个月前IP:四川
796108
11楼
引用 张静茹:
只用SetWindowText改变Text还是会自动把光标设置为0 滚动条在最上面,使用你的SetWindowText和我原来办法就完美了~~~
        
        public static extern int Set...
这里应该改成CharSet = CharSet.Auto或CharSet.Unicode。。。不然很多字符都可能变成一堆问号
使用CharSet.Ansi的话,.NET要先把string从unicode转换为ansi字符串,然后调用SetWindowTextA,然后SetWindowTextA再把ansi字符串转换成unicode调用SetWindowTextW。。。与其这样不如直接使用CharSet.Auto或CharSet.Unicode,这样.NET会直接调用SetWindowTextW。
引用
评论
张静茹作者
11年1个月前IP:山东
796160
12楼
引用 acmilan:
这里应该改成CharSet = CharSet.Auto或CharSet.Unicode。。。不然很多字符都可能变成一堆问号
使用CharSet.Ansi的话,.NET要先把string从unicode转换为ansi字符串,然后调用Set...
恩 是的
引用
评论
张静茹作者
11年1个月前IP:山东
796168
13楼
引用 acmilan:
c++中调用基类的基类的函数是常见语法(Control::setText)
这得是Control的setText方法是public吧
引用
评论
11年1个月前IP:四川
796203
14楼
引用 张静茹:
这得是Control的setText方法是public吧
应该protected就行
引用
评论
张静茹作者
11年1个月前IP:山东
796235
15楼
引用 acmilan:
应该protected就行
C#的多态特性,TextBox继承TextBoxBase,它再继承Control,TextBox里的Text属性是override修饰的,继承链中的text都被他覆盖了,好像不能访问Control的Text了
引用
评论
11年1个月前IP:四川
796264
16楼
引用 张静茹:
C#的多态特性,TextBox继承TextBoxBase,它再继承Control,TextBox里的Text属性是override修饰的,继承链中的text都被他覆盖了,好像不能访问Control的Text了
c++中如果setText是虚函数(可以被子类重写的函数)的话,setText()是call this->vtable[n_setText],而Control::setText()则是call Control::setText。c#的base.Text应该也类似,只是可能不能随意跨级调用而已。
引用
评论
张静茹作者
11年1个月前IP:山东
796317
17楼
引用 acmilan:
c++中如果setText是虚函数(可以被子类重写的函数)的话,setText()是call this->vtable,而Control::setText()则是call Control::setText。c#的base.Text应该也类似...


typeof(Control).GetProperty("WindowText", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).
    SetValue(textBox1, "在TextBox里显示的内容");

TextBox.Text直接调用TextBoxBase的Text,它再调用Control的Text,然后再给ConTrol的WindowText,这个属性声明为内部,是访问不到的,Text否是子类覆写父类的,子类根本调用不到父类的Text

我用这段代码直接用反射得到了Control的WindowText,然而还是没卵用,修改了textBox1的Text后光标和滚动条还是会动,但是不会全选了,跟直接使用SetWindowText是一样的


刚才又试了一下 这个办法对Label Button是没用的,奇怪他们的Text都是一样的呀,最后都是Control的WindowTex
引用
评论
11年1个月前IP:四川
796325
18楼
引用 张静茹:
typeof(Control).GetProperty("WindowText", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Publ...
this.selectionSet = false;应该就是全选的作用。mfc中替换文本的做法好像就是你这么做的。
引用
评论
张静茹作者
11年1个月前IP:山东
796326
19楼
引用 acmilan:
this.selectionSet = false;应该就是全选的作用。mfc中替换文本的做法好像就是你这么做的。
应该是的,this.selectionSet = false;是在TextBox里的,跳过了TextBox确实不会全选了
引用
评论
11年1个月前IP:四川
796330
20楼
引用 张静茹:
应该是的,this.selectionSet = false;是在TextBox里的,跳过了TextBox确实不会全选了
→_→我不知道.net加上这一句有什么用
引用
评论
张静茹作者
11年0个月前IP:山东
799045
21楼
引用 acmilan:
→_→我不知道.net加上这一句有什么用

终于解决了,这样滚动条就不会变了
var SelectInternal = typeof(RichTextBox).GetMethod("SelectInternal", BindingFlags.Instance | BindingFlags.NonPublic);
SelectInternal.Invoke(richTextBox1, new object[]{1000,1000,1000});//要插入的位置,三个参数 好像必须一样原型:internal virtual void SelectInternal(int start, int length, int textLen)
richTextBox1.SelectedText = "要插入的文本";
引用
评论
张静茹作者
11年0个月前IP:山东
799120
22楼
richTextBox1.Enabled = false;
//Application.DoEvents();
richTextBox1.Rtf = richTextBox2.Rtf;
richTextBox1.Enabled = true;


又发现一个办法
引用
评论
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的