заставить winforms textbox вести себя как адресная строка вашего браузера

<p>когда текстовое поле c # winforms получает фокус, я хочу, чтобы оно велось как адресная строка вашего браузера.</p><p>чтобы понять, что я имею в виду, нажмите в адресной строке вашего браузера. вы заметите следующее поведение:</p><ol> <li>нажатие в текстовом поле должно выделить весь текст, если текстовое поле не было предварительно сфокусировано.</li> <li>мышь вниз и перетаскивание в текстовое поле должны выбрать только текст, который я выделил мышью.</li> <li>если текстовое поле уже выделено, нажатие не выделяет весь текст.</li> <li>фокусируя текстовое поле программно или с помощью клавиатуры, следует выделить весь текст.</li> </ol><p>я хочу сделать именно это в winforms.</p><p><strong>fastest gun alert: пожалуйста, прочитайте следующее, прежде чем ответить!</strong> спасибо, ребята. :-)</p><blockquote> <p><strong>вызов .selectall () во время событий .enter или .gotfocus не будет работать</strong>, потому что если пользователь щелкнул текстовое поле, курсор будет помещен туда, где он щелкнул, и, таким образом, отменит выбор всего текста.</p> <p><strong>вызов .selectall () во время события .click не будет работать</strong>, потому что пользователь не сможет выделить текст мышью; вызов .selectall () будет перезаписывать выделенный текст пользователя.</p> <p><strong>вызов функции begininvoke ((action) textbox.selectall) при вводе события focus/enter не работает</strong>, поскольку он нарушает правило № 2, описанное выше, он будет переопределять выбор пользователя в фокусе.</p> </blockquote>

<p>прежде всего, спасибо за ответы! 9 всего ответов. спасибо.</p><p>плохая новость: все ответы имели некоторые причуды или работали не совсем правильно (или вообще). я добавил комментарий к каждому из ваших постов.</p><p>хорошие новости: я нашел способ заставить это работать. это решение довольно простое и, похоже, работает во всех сценариях (наведение мыши, выбор текста, фокусировка на вкладках и т.д.)</p><pre><code>bool alreadyfocused; ... textbox1.gotfocus += textbox1\_gotfocus; textbox1.mouseup += textbox1\_mouseup; textbox1.leave += textbox1\_leave; ... void textbox1\_leave(object sender, eventargs e) { alreadyfocused = false; } void textbox1\_gotfocus(object sender, eventargs e) { // select all text only if the mouse isn't down. // this makes tabbing to the textbox give focus. if (mousebuttons == mousebuttons.none) { this.textbox1.selectall(); alreadyfocused = true; } } void textbox1\_mouseup(object sender, mouseeventargs e) { // web browsers like google chrome select the text on mouse up. // they only do it if the textbox isn't already focused, // and if the user hasn't selected all text. if (!alreadyfocused && this.textbox1.selectionlength == 0) { alreadyfocused = true; this.textbox1.selectall(); } } </code></pre><p>насколько я могу судить, это приводит к тому, что текстовое поле ведет себя точно так же, как адресная строка веб-браузера.</p><p>надеюсь, это поможет следующему парню, который пытается решить эту обманчиво простую проблему.</p><p>еще раз спасибо, ребята, за все ваши ответы, которые помогли привести меня к правильному пути.</p>

<p>я нашел более простое решение для этого. он включает в себя асинхронное отключение selectall с использованием <code>control.begininvoke</code>, чтобы оно происходило после того, как произошли события enter и click:</p><p>в c #:</p><pre><code>private void mytextbox\_enter(object sender, eventargs e) { // kick off selectall asyncronously so that it occurs after click begininvoke((action)delegate { mytextbox.selectall(); }); } </code></pre><p>в vb.net (спасибо <a href="https://stackoverflow.com/users/1309193/krishanu-dey">кришану дей</a> )</p><pre><code>private sub mytextbox\_enter(sender as object, e as eventargs) handles mytextbox.enter begininvoke(directcast(sub() mytextbox.selectall(), action)) end sub </code></pre>

<p>ваше решение хорошо, но не в одном конкретном случае. если вы фокусируете textbox, выбирая диапазон текста, а не просто щелкаете мышью, то для флага уже установленного фокуса не устанавливается значение true, поэтому при повторном щелчке по текстовому блоку выделяется весь текст.</p><p>вот моя версия решения. я также поместил код в класс, который наследует textbox, поэтому логика скрыта.</p><pre><code>public class mytextbox : system.windows.forms.textbox { private bool \_focused; protected override void onenter(eventargs e) { base.onenter(e); if (mousebuttons == mousebuttons.none) { selectall(); \_focused = true; } } protected override void onleave(eventargs e) { base.onleave(e); \_focused = false; } protected override void onmouseup(mouseeventargs mevent) { base.onmouseup(mevent); if (!\_focused) { if (selectionlength == 0) selectall(); \_focused = true; } } } </code></pre>

<p>это немного хитро, но в вашем событии клика используйте <code>sendkeys.send( "{home}+{end}" );</code>.</p>

<p>ответ в одну строку, который я использую ... вы можете пнуть себя ...</p><p>в событии enter:</p><p>txtfilter.begininvoke (новый methodinvoker (txtfilter.selectall));</p>

<p>нажмите событие текстового поля? или даже событие mousecapturechanged работает для меня. - хорошо. не работает.</p><p>таким образом, вы должны сделать 2 вещи:</p><pre><code>private bool f = false; private void textbox\_mouseclick(object sender, mouseeventargs e) { if (this.f) { this.textbox.selectall(); } this.f = false; } private void textbox\_enter(object sender, eventargs e) { this.f = true; this.textbox.selectall(); } private void textbox\_mousemove(object sender, mouseeventargs e) // idea from the other answer { this.f = false; } </code></pre><p>работает и для табуляции (через textboxes к одному) - вызовите selectall () в enter на всякий случай ...</p>

<p>вот вспомогательная функция, которая выводит решение на новый уровень - повторное использование без наследования.</p><pre><code> public static void wireselectallonfocus( textbox atextbox ) { bool lactive = false; atextbox.gotfocus += new eventhandler( ( sender, e ) => { if ( system.windows.forms.control.mousebuttons == mousebuttons.none ) { atextbox.selectall(); lactive = true; } } ); atextbox.leave += new eventhandler( (sender, e ) => { lactive = false; } ); atextbox.mouseup += new mouseeventhandler( (sender, e ) => { if ( !lactive ) { lactive = true; if ( atextbox.selectionlength == 0 ) atextbox.selectall(); } }); } </code></pre><p>чтобы использовать это, просто вызовите функцию, передающую textbox, и она позаботится обо всех ваших проблемах. я предлагаю соединить все ваши текстовые поля в событии form\_load. вы можете разместить эту функцию в своей форме или, если хотите, как я, где-нибудь в служебном классе для еще большего повторного использования.</p>

<pre><code>'inside the enter event textbox1.selectall(); </code></pre><p>хорошо, после попытки вот что вы хотите:</p><ul> <li>в событии enter запустите флаг, который указывает, что вы были в событии enter</li> <li>на событии click, если вы установите флаг, вызовите .selectall () и сбросьте флаг.</li> <li>в случае mousemove установите флаг ввода в значение false, что позволит вам щелкнуть выделение, не вводя сначала текстовое поле.</li> </ul><p>это выделило весь текст при вводе, но позволило мне выделить часть текста впоследствии или позволить выделить при первом щелчке.</p><p>по запросу:</p><pre><code> bool entered = false; private void textbox1\_enter(object sender, eventargs e) { entered = true; textbox1.selectall(); //from jakub's answer. } private void textbox1\_click(object sender, eventargs e) { if (entered) textbox1.selectall(); entered = false; } private void textbox1\_mousemove(object sender, mouseeventargs e) { if (entered) entered = false; } </code></pre><p>для меня вкладка в элемент управления выделяет весь текст.</p>

<p>это сработало для текстового поля wpf/xaml.</p><pre><code> private bool initialentry = true; private void textbox\_selectionchanged(object sender, routedeventargs e) { if (initialentry) { e.handled = true; initialentry = false; textbox.selectall(); } } private void textbox\_gotfocus(object sender, routedeventargs e) { textbox.selectall(); initialentry = true; } </code></pre>

<p>это похоже на популярный ответ <a href="https://stackoverflow.com/a/3678888/7444103">nzhenry</a> , но мне легче не иметь подкласса:</p><pre class="lang-vb prettyprint-override"><code>private lastfocused as control = nothing private sub textbox1\_enter(sender as object, e as system.eventargs) handles textbox1.enter, textbox2.enter, textbox3.enter if mousebuttons = windows.forms.mousebuttons.none then lastfocused = sender end sub private sub textbox1\_leave(sender as object, e as system.eventargs) handles textbox1.leave, textbox2.leave, textbox3.leave lastfocused = nothing end sub private sub textbox1\_mouseup(sender as object, e as system.windows.forms.mouseeventargs) handles textbox1.mouseup, textbox2.mouseup, textbox3.mouseup with ctype(sender, textbox) if lastfocused isnot sender andalso .selectionlength = 0 then .selectall() end with lastfocused = sender end sub </code></pre>

<p>я нашел еще более простое решение:</p><p>чтобы убедиться, что весь текст выделен при нажатии на текстовое поле, убедитесь, что обработчик click вызывает обработчик enter. нет необходимости в дополнительных переменных!</p><p>пример:</p><pre><code>private void textbox1\_click(object sender, eventargs e){ textbox1\_enter(sender, e); } private void textbox1\_enter(object sender, eventargs e){ textbox tb = ((textbox)sender); tb.selectall(); } </code></pre>

<p>selectall никогда не работал для меня.</p><p>это работает.</p><pre><code>activecontrol = textbox1; textbox1->selectionstart = 0; textbox1->selectionlength = textbox1->text->length; </code></pre>

<p>почему бы вам просто не использовать mousedown-event текстового поля? он отлично работает для меня и не нуждается в дополнительном логическом значении. очень чисто и просто, например:</p><pre><code>private void textbox\_mousedown(object sender, mouseeventargs e) { if (textbox != null && !string.isnullorempty(textbox.text)) { textbox.selectall(); } } </code></pre>

<p>на самом деле gotfocus - это правильное событие (действительно сообщение), которое вас интересует, так как независимо от того, как вы доберетесь до контроля, вы получите это даже в конце концов. вопрос в том, когда вы вызываете selectall ().</p><p>попробуй это:</p><pre><code>public partial class form1 : form { public form1() { initializecomponent(); this.textbox1.gotfocus += new eventhandler(textbox1\_gotfocus); } private delegate void selectalldelegate(); private iasyncresult \_selectallar = null; //so we can clean up afterwards. //catch the input focus event void textbox1\_gotfocus(object sender, eventargs e) { //we could have gotten here many ways (including mouse click) //so there could be other messages queued up already that might change the selection. //don't call selectall here, since it might get undone by things such as positioning the cursor. //instead use begininvoke on the form to queue up a message //to select all the text after everything caused by the current event is processed. this.\_selectallar = this.begininvoke(new selectalldelegate(this.\_selectall)); } private void \_selectall() { //clean-up the begininvoke if (this.\_selectallar != null) { this.endinvoke(this.\_selectallar); } //now select everything. this.textbox1.selectall(); } } </code></pre>

<p>установите выбор, когда вы покидаете контроль. это будет там, когда ты вернешься. нажмите на форму и, когда вы вернетесь к элементу управления, будет выделен весь текст.</p><p>если вы нажмете мышкой, то каретка будет правильно размещена в том месте, где вы щелкнули.</p><pre><code>private void maskedtextbox1\_leave(object sender, canceleventargs e) { maskedtextbox1.selectall(); } </code></pre>

<p>интересно, что combobox с dropdownstyle = simple, похоже, имеет именно то поведение, которое вы ищете.</p><p>(если вы уменьшите высоту элемента управления, чтобы список не отображался, а затем еще на пару пикселей, эффективная разница между combobox и textbox отсутствует).</p>

<p>вы пробовали <a href="http://social.msdn.microsoft.com/forums/en-us/winforms/thread/e0d183d7-5bfe-4e68-abbb-fba9fdd209fd/">решение, предложенное на форуме msdn "windows forms general"</a> , которое просто подклассов textbox?</p>

<p>следующее решение работает для меня. я добавил переопределение событий <code>onkeydown</code> и <code>onkeyup</code>, чтобы текст textbox оставался всегда выделенным.</p><pre><code> public class numerictextbox : textbox { private bool \_focused; protected override void ongotfocus(eventargs e) { base.ongotfocus(e); if (mousebuttons == mousebuttons.none) { this.selectall(); \_focused = true; } } protected override void onenter(eventargs e) { base.onenter(e); if (mousebuttons == mousebuttons.none) { selectall(); \_focused = true; } } protected override void onleave(eventargs e) { base.onleave(e); \_focused = false; } protected override void onmouseup(mouseeventargs mevent) { base.onmouseup(mevent); if (!\_focused) { if (selectionlength == 0) selectall(); \_focused = true; } } protected override void onkeyup(keyeventargs e) { base.onkeyup(e); if (selectionlength == 0) selectall(); \_focused = true; } protected override void onkeydown(keyeventargs e) { base.onkeydown(e); if (selectionlength == 0) selectall(); \_focused = true; } } </code></pre>

<p>я вызвал selectall внутри события mouseup, и у меня все заработало.</p><pre><code> private bool \_tailtextboxfirstclick = false; private void textbox1\_mouseup(object sender, mouseeventargs e) { if(\_textboxfirstclick) textbox1.selectall(); \_textboxfirstclick = false; } private void textbox1\_leave(object sender, eventargs e) { \_textboxfirstclick = true; textbox1.select(0, 0); } </code></pre>

<p>мое решение довольно примитивно, но отлично работает для моих целей</p><pre><code>private async void textbox\_gotfocus(object sender, routedeventargs e) { if (sender is textbox) { await task.delay(100); (sender as textbox).selectall(); } } </code></pre>

<p>я знаю, что это уже было решено, но у меня есть предположение, которое я считаю довольно простым.</p><p>в событии мыши вверх все, что вам нужно сделать, это поместить</p><pre><code>if(textbox.selectionlength = 0) { textbox.selectall(); } </code></pre><p>кажется, это работает для меня в vb.net (я знаю, что это вопрос c # ... к сожалению, я вынужден использовать vb на своей работе ... и у меня возникла эта проблема, что привез меня сюда...)</p><p>я не нашел никаких проблем с этим .. за исключением того факта, что он не сразу выбирает при нажатии, но у меня были проблемы с этим ....</p>

<p>для группы текстовых полей в форме:</p><pre><code>private system.windows.forms.textbox lastfocus; private void textbox\_gotfocus(object sender, system.windows.forms.mouseeventargs e) { textbox sendertextbox = sender as textbox; if (lastfocus!=sendertextbox){ sendertextbox.selectall(); } lastfocus = sendertextbox; } </code></pre>

<pre><code>private bool \_isselected = false; private void textbox\_validated(object sender, eventargs e) { \_isselected = false; } private void textbox\_mouseclick(object sender, mouseeventargs e) { selectalltext(textbox); } private void textbox\_enter(object sender, eventargs e) { selectalltext(textbox); } private void selectalltext(textbox text) { if (!\_isselected) { \_isselected = true; textbox.selectall(); } } </code></pre>

<p>ответ может быть на самом деле более простым, чем все из вышеперечисленного, например (в wpf):</p><pre><code>public void yourtextbox\_mouseenter(object sender, mouseeventargs e) { yourtextbox.focus(); yourtextbox.selectall(); } </code></pre><p>конечно, я не могу знать, как вы хотите использовать этот код, но основная часть, на которую стоит обратить внимание, это: сначала вызов .focus (), а затем вызов .selectall ();</p>

<p>я считаю эту работу лучше всего, когда щелчок мышью не сразу отпущен:</p><pre><code> private bool searchboxinfocusalready = false; private void searchbox\_lostfocus(object sender, routedeventargs e) { searchboxinfocusalready = false; } private void searchbox\_previewmouseup(object sender, mousebuttoneventargs e) { if (e.buttonstate == mousebuttonstate.released && e.changedbutton == mousebutton.left && searchbox.selectionlength == 0 && searchboxinfocusalready == false) { searchbox.selectall(); } searchboxinfocusalready = true; } </code></pre>

<p>очень простое решение:</p><pre><code> private bool \_focusing = false; protected override void onenter( eventargs e ) { \_focusing = true; base.onenter( e ); } protected override void onmouseup( mouseeventargs mevent ) { base.onmouseup( mevent ); if( \_focusing ) { this.selectall(); \_focusing = false; } } </code></pre><p><strong>edit:</strong> оригинальный op, в частности, был обеспокоен последовательностью мыши-вниз/выбора текста/мыши-вверх, и в этом случае простое решение, приведенное выше, в конечном итоге было бы частично выделено.</p><p>это должно решить * проблему (на практике я перехватываю wm\_setcursor):</p><pre><code> protected override void wndproc( ref message m ) { if( m.msg == 32 ) //wm\_setcursor=0x20 { this.selectall(); // or your custom logic here } base.wndproc( ref m ); } </code></pre><p>* на самом деле следующая последовательность заканчивается частичным выделением текста, но затем, если вы наведете указатель мыши на текстовое поле, весь текст будет выделен снова:</p><p>мышь-вниз/выделение текста/мышь-перемещение-текстовое поле/мышь вверх</p>

<p>просто используйте selectall () при вводе и клике по событиям</p><pre><code>private void textbox1\_enter(object sender, eventargs e) { textbox1.selectall(); } private void textbox1\_click(object sender, eventargs e) { textbox1.selectall(); } </code></pre>

<p>это работает для меня в .net 2005 -</p><pre><code> ' * if the mouse button is down, do not run the select all. if mousebuttons = windows.forms.mousebuttons.left then exit sub end if ' * otherwise invoke the select all as discussed. </code></pre>

<p>ниже, кажется, работает. событие enter обрабатывает вкладки для элемента управления, а mousedown работает при нажатии на элемент управления.</p><pre><code> private ########### void textbox1\_enter(object sender, eventargs e) { textbox1.selectall(); } private void textbox1\_mousedown(object sender, mouseeventargs e) { if (textbox1.focused) textbox1.selectall(); } </code></pre>

<p>просто выведите класс из textbox или maskedtextbox:</p><pre><code>public class smaskedtextbox : maskedtextbox { protected override void ongotfocus(eventargs e) { base.ongotfocus(e); this.selectall(); } } </code></pre><p>и используйте это на своих формах.</p>