Hallo,
mein Ziel ist es so eine Suchfunktion wie es im Editor unter Windows angeboten wird mit WPF und C# zu programmieren. Die gesuchten Wörter sollen bei mir in einer TextBox im Hauptfenster (MainWindow) entsprechend des eingegeben Wortes im Nebenfenster (Subfenster) markiert werden.
Die Suche und die Markierung des gesuchten Wortes funktioniert soweit, wenn der "Suchen"-Button sich im Hauptfenster befindet. Ist der Suchen-Button im Nebenfenster platziert, ist die Markierung des gesuchten Wortes im Hauptfenster nicht zu sehen. Das Problem liegt hierbei darin, dass der Fokus auf dem Nebenfenster gesetzt wird wenn ich ein Element darin anklicke. Entsprechend verliert der TextBox im Hauptfenster den Fokus.
Ich habe folgendes versucht:
//Setzt den Fokus auf MainWindow und markiert dort das gesuchte Wort
private void ButtonSuchen_Click(object sender, RoutedEventArgs e)
{
SetFocusToMainWindow();
TextSelection(TextBoxSearch.Text); //markiert das gesuchte Wort
}
//Setzt den Fokus auf MainWindow
void SetFocusToMainWindow()
{
var myMainWindow = (MainWindow)Application.Current.MainWindow;
myMainWindow.Activate();
myMainWindow.Topmost = true;
myMainWindow.Topmost = false;
myMainWindow.Focus();
Keyboard.Focus(myMainWindow.TextBoxAusgabe);
this.Topmost = true;
}
Hier wird das gesuchte Wort im Hauptfenster dann markiert angezeigt. Allerdings gibt es noch 2 Probleme
Für Hilfestellungen wäre ich dankbar.
Hi spry64,
das scheint ein Windows-spezifisches Verhalten zu sein. Evtl. wäre eine Lösung, die Markierung selbst zu zeichnen, z.B. mit einem FlowDocument, oder ein anderes Steuerelement für den Text zu verwenden (RichTextBox, AvalonEdit o.ä.). Aber vielleicht wäre das hier die einfachste Lösung:
Die Suche und die Markierung des gesuchten Wortes funktioniert soweit, wenn der "Suchen"-Button sich im Hauptfenster befindet.
Also so, wie es z.B. im FireFox umgesetzt ist.
Weeks of programming can save you hours of planning
Also ich habe eine Halblösung für mein Problem gefunden. Wenn man den folgenden Code schreibt:
private void TextBoxLostFocusEvent(object sender, RoutedEventArgs e)
{
e.Handled = true;
}
bleibt die Markierung erhalten. Das geht aber nur wenn man das Fenster zum Suchen über einen Button öffnet. Bei mir ist es aber ein MenuItem und da klappt das nicht 😕
Das was du da vorhast mit der Selection-Fuktionalität umzusetzen ist wie mit einem Hammer die Haare kämmen.
Entweder es tut zu doll weh oder die Haare liegen nicht richtig.
Und warum?
Die Hauptintention des Hammers ist nun mal nicht Haare kämmen sondern Nägel in die Wand kloppen.
Die Hauptintention der Selection ist die Signalisierung für den Anwender, was beim nächsten Tastendruck ersetzt wird, bzw. was bei Strg-C in die Zwischenablage geht. Das mit dem LostFocusEvent wird eher darauf hinauslaufen den Anwender zu verwirren.
Die RichTextBox kann sowas(, das hat MrSparkle aber schon mal erwähnt 😉
Die kann InlineUIContainer aufnehmen und da kannst Du dann praktisch alles rein packen.
Die Controls liegen dann im Text an der Stelle, wo es eingebaut wurde.
Da packst Du dann irgendwas rein, was den selben Text darstellt, aber z.B. mit Rahmen drum herum.
Wobei ich glaube, dass die eigentliche Magie dazu eher in dem FlowDocument liegt, das nutzt Du bei der RichTextBox nämlich auch. (Kannst ja mal ausprobieren, obs auch ohne die RichTextBox geht.
NuGet Packages im Code auslesen
lock Alternative für async/await
Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.
Die Hauptintention der Selection ist die Signalisierung für den Anwender, was beim nächsten Tastendruck ersetzt wird.
Das Ersetzen soll natürlich auch möglich sein, so wie es im Editor der Fall ist.
Wenn das Feld aber den Focus nicht hat, dann wird das aber nicht funktionieren obwohl der Benutzer es erwarten würde (weil es ja so aussieht als ob es gehen müsste).
Dazu müsste der Benutzer den Focus wieder auf die TextBox setzen und dabei kann auch die Selection wieder zurückgesetzt werden.
Die RichTextBox kann sowas:::
Ja hätte ich auch gewählt, aber die Aufgabenstellung lässt es nicht zu.
Wie gesagt: das ganze funktioniert auch solange ich das Fenster zum Suchen über einen Button öffne. Es geht aber nicht wenn ich das Fenster über ein MenuItem öffne.
"e.Handled = true" verhindert ja dass der Focus zurückgesetzt wird. Wenn ich das Suchen-Fenster über den MenuItem öffne kommt es gar nicht zu dem TextBoxLostFocusEvent.
Das ist doch auch logisch, dass bei einer Menü-Auswahl der Focus nicht verloren geht, oder wie würde es sonst möglich sein den Menüpunkt Bearbeiten/Kopieren (und seine Kollegen) erfolgreich auszuführen?
Das ist doch auch logisch, dass bei einer Menü-Auswahl der Focus nicht verloren geht, oder wie würde es sonst möglich sein den Menüpunkt Bearbeiten/Kopieren (und seine Kollegen) erfolgreich auszuführen?
Ja und die Frage ist nun warum ist die Markierung nicht zu sehen, wenn der Focus erhalten bleibt?
Nun du öffnest ja ein neues Fenster und dadurch verliert das Fenster mit der TextBox den Focus und deswegen wird die Selection nicht mehr angezeigt.
Nun du öffnest ja ein neues Fenster und dadurch verliert das Fenster mit der TextBox den Focus und deswegen wird die Selection nicht mehr angezeigt.
Ja aber dann müsste doch TextBoxLostFocusEvent abgefeuert werden wenn der den Fokus verliert ^^
Also ich habe noch folgendes versucht: Im Loaded-Event des Suchfensters die IsFocused Eigenschaft des TextBoxes ausgegeben. Wenn ich das Fenster über den Button öffne ist der Wert "False" und wenn ich es über den MenuItem aufrufe ist der "True". Jetzt versteh ich gar nichts mehr.
Nun ja, wenn du auf den Button drückst, dann hat der Button den Focus 😁
Nun ja, wenn du auf den Button drückst, dann hat der Button den Focus 😄
Ja und hier dann wieder die Frage: warum wird die Selection dann angezeigt und warum nicht über den MenuItem obwohl der Wert IsFocused true ist?
Das könntest du im Quelltext der TextBox
bzw. wohl eher TextBoxBase
nachlesen.
Vom Prinzip her, weiß das Control selber ob es den Focus hat oder eben nicht, und ob das Anzeige-Fenster den Focus hat. Nur wenn beide Punkte erfüllt sind, dann wird die Selection angezeigt.
Allerdings könntest du ja mal die Eigenschaft TextBoxBase.IsInactiveSelectionHighlightEnabled
anschauen, die riecht irgendwie danach, als ob die dir behilflich sein könnte. 😉
~~Kennst du schon TextBoxBase.HideSelection?
You can use this property to keep text highlighted in a text box control while another form or a dialog box has focus, such as a spelling checker dialog box. ~~
Siehe dazu die Beiträge von Sir Rufo.
Weeks of programming can save you hours of planning
Kennst du schon
> ?
Bei einer WinForms-Anwendung wäre das der richtige Hinweis, aber bei WPF heißt die Eigenschaft eben anders 🙂
Warum solltest Du sie nicht nutzen können?
Geht jetzt aus Deiner Frage nicht hervor.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Compiler erkennt es nicht. Beispiel:
TextBoxAusgabe.IsInactiveSelectionHighlightEnabled = true;
Meldung: "System.Windows.Controls.TextBox does not contain a defintion for IsInactiveSelectionHighlightEnabled"
Du hast die Doku gelesen? Komplett?
Auch, ab welcher .net Version diese Eigenschaft vorhanden ist?
Welche Doku ist genau gemeint?
Ich habe es mit VS 2012 Express und VS 2017 Community probiert. Klappt bei beidem nicht.
ab welcher .net Version diese Eigenschaft vorhanden ist?
Ab Version 4.5
Ich arbeite mit der Version 4.7.02053 unter VS 2012
@spry64
Hast du dann mal deine .Net Version geprüft/geändert?
Kann eigentlich nur sein, dass du eine Version vor 4.5 benutzt, da die TextBox die Property in neueren Versionen haben muss.
Da die Klasse Textbox auch von der TextBoxBase Klasse abgeleiet wird, sollte die Property direkt da sein.
Nachtrag:
Sicher dass es VS 2012 mit .Net 4.7 ist?
Kann mir nicht vorstellen, dass VS 2012 noch .Net 4.7 Support erhalten hat.
Bei VS 2015 gab es mit Update 2 oder 3 erst den Support aber bei VS 2012 kann ich es mir nicht vorstellen.
T-Virus
Developer, Developer, Developer, Developer....
99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
Wie gesagt unter "Hilfe" und dann "Über Visual Studio 2012 Express..." wird die Version 4.7 angezeigt.
@spry64
Hattest du dazu die Entwickler Packs installiert?
Scheinbar müssen diese bei VS 2012 installiert werden, damit 4.7 supportet wird.
Deine .Net Version musst du aber in der Projektmappe einstellen.
Unter Hilfe siehst du nur die Infos zu Visual Studio aber nicht zu deinem Ziel Framework im Projekt gegen das du entwickelst.
Hier dürfte der Hase begraben sein, also dort einmal unter Projektmappen Einstellungen die .Net Version auf 4.5+ einstellen.
Ansonsten würde ich diret zu VS 2017 greifen, wenn von deiner Seite nichts dagegenspricht.
Dann kannst du gleich auf der richtigen Basis arbeiten, was auch Zukunftssicherer ist als VS 2012.
Prüf mal ob dort das Problem noch besteht.
Dürfte eigentlich nicht der Fall sein, wenn alles richtig eingestellt ist.
T-Virus
Developer, Developer, Developer, Developer....
99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
Bitte keine Fullquotes. Bitte beachte [Hinweis] Wie poste ich richtig? (Punkt 2.3)!
Weeks of programming can save you hours of planning
Diese Eigenschaft trägt aber leider nicht zur Lösung des ursprünglichen Problems bei. Der Wert ist die ganze Zeit nun auf "true".
Das ursprüngliche Problem ist wahrscheinlich, daß du da etwas zusammengefrickelt hast, was so nicht deinen Anforderungen entspricht. Ich kann mir auch beim besten Willen nicht vorstellen, daß man im Internet keine Beispiele oder Open-Source-Projekte finden kann, bei denen eine solche Suchfunktion in einem eigenen Dialog implementiert ist und wie von dir gewünscht funktioniert.
Weeks of programming can save you hours of planning
Kann ich so nicht nachvollziehen. Ich habe es selber ausprobiert und die Selektion wird weiterhin angezeigt auch wenn der Fokus auf einem anderen Fenster liegt.
Eventuell beschreibst du mal (mit Source und ScreenShot) was denn nun nicht funktioniert.
@Sir Rufo
wie schon oben erwähnt funktioniert die Selection nicht wenn ich das Fenster zum Suchen über ein MenuItem aufrufe. An diesem Verhalten änderte die Eigenschaft IsInactiveSelectionHighlightEnabled auch nichts.
In meinen Screenshots sieht man einmal den Code in der "MainWindow" wo der Focus auf den TextBox gesetzt wird und die Eigenschaft IsInactiveSelectionHighlightEnabled auf true gesetzt wird und einmal den Code für das "TestWindow" das zum Suchen geöffnet wird. Da wird mit dem Klick auf dem Button zwei Stellen des Textbereichs im TextBox abwechselnd markiert. Die Selektion funktioniert wenn ich das Fenster zum Suchen über einen Button aufrufe, aber nicht über MenuItem.
Hmmm, den Source kann man hier wunderbar als Text posten (Code-Tags verwenden). Ein ScreenShot ist nur von der Anzeige notwendig.
Warum hast du denn immer noch dieses LostFocus-Gedöns da drin? Nimm das raus und schau es dir dann an.
Bitte den Code und das XAML als Text posten, danke. =)
Bitte:
MainWindow:
namespace TextBoxFocusTest
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TextBoxAusgabe.Text = "Dies ist ein Text zum Testen\nob die Markierung ohne Fokus\nangezeigt wird";
TextBoxAusgabe.Focus();
TextBoxAusgabe.IsInactiveSelectionHighlightEnabled = true;
}
private void TextBoxLostFocusEvent(object sender, RoutedEventArgs e)
{
e.Handled = true;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
TestWindow tw = new TestWindow();
tw.mainWindowRef = this;
tw.ShowDialog();
}
private void MenuItemSearch_Click(object sender, RoutedEventArgs e)
{
TestWindow tw = new TestWindow();
tw.mainWindowRef = this;
tw.ShowDialog();
}
}
}
TestWindow:
namespace TextBoxFocusTest
{
/// <summary>
/// Interaktionslogik für TestWindow.xaml
/// </summary>
public partial class TestWindow : Window
{
public MainWindow mainWindowRef;
bool toggle = false;
public TestWindow()
{
InitializeComponent();
this.Owner = Application.Current.MainWindow;
this.Left = Application.Current.MainWindow.Left + Application.Current.MainWindow.Width - this.Width;
this.Top = (Application.Current.MainWindow.Top + Application.Current.MainWindow.Height - this.Height) / 2;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var myMainWindow = (MainWindow)Application.Current.MainWindow;
if (toggle == false)
{
myMainWindow.TextBoxAusgabe.Select(58, 9);
toggle = true;
}
else {
myMainWindow.TextBoxAusgabe.Select(52, 5);
toggle = false;
}
}
}
}
XAML:
<Window x:Class="TextBoxFocusTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Name="TextBoxAusgabe" LostFocus="TextBoxLostFocusEvent" HorizontalAlignment="Left" Height="223" Margin="10,37,0,0"
TextWrapping="Wrap" VerticalAlignment="Top" Width="497"/>
<Button Content="Öffne Fenster" HorizontalAlignment="Left" Margin="10,265,0,0" VerticalAlignment="Top" Width="115"
RenderTransformOrigin="-0.076,0.371" Click="Button_Click_1"/>
<Menu HorizontalAlignment="Left" Height="27" VerticalAlignment="Top" Width="517">
<MenuItem Name="MenuItemFile" Header="_Datei">
<MenuItem Name="MenuItemSearch" Header="_Suchen / Ersetzen" Click="MenuItemSearch_Click" />
</MenuItem>
</Menu>
</Grid>
</Window>
@spry64
Es ist nie hilfreich Bilder vom Code zu posten.
Niemand hat Lust Codes von Bildern abzutippen.
Das Forum hat dafür extra Tags, damit man seinen code mit richtigen Style posten kann.
Nachtrag:
Hat sich gerade erledigt!
T-Virus
Developer, Developer, Developer, Developer....
99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.
Also wo soll man da anfangen?
Zunächst mal benötigt es eine saubere Trennung zwischen Main- und SubWindow.
Das SubWindow müßte ein Event bereitstellen, daß jedesmal dann gefeuert wird, wenn sich der Suchtext ändert.
Im MainWindow kann man dann mit diesem Event auf diese Wertänderung reagieren.
Momentan werden beide Fenster komplett verstrickt. Mal abgesehen das das sehr unschön ist, zudem das Suchfenster nur für das MainWindow verwendet werden kann, sonst für nix.
[Edit1]
Zudem würd ich, bevor man hier versucht Funktionen umzusetzen, mich mal mit DataBindings auseinandersetzen. Alles was im XAML möglich ist zu definieren (alles rein UI spezifische) auch dort umsetzen, nicht im Code.
Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄
@ Sir Rufo
ich habe den "TextBoxLostFocusEvent" auskommentiert. Jetzt funktioniert die Selektion nicht mal mit dem Button
@ ThomasE
Das ganze hat wenig mit der Änderung des Suchtextes zu tun. Du willst z.B. nach "Benutzer" suchen, so klickst du dann mehrmals auf den Button "Weitersuchen" ohne dass sich der Text ändert. Bitte einmal bei dem Programm Editor ausprobieren wie es funktionieren soll.
Warum machst du dir eigentlich so eine Mühe mit dieser Frickelei? Geh doch lieber mal ein bißchen strukturierter vor, dann kann man das ganze auch vernünftig testen und debuggen. Wir haben hier im Forum auch einige Artikel dazu, z.B. [FAQ] Kommunikation von 2 Forms, [Artikel] Drei-Schichten-Architektur, [Artikel] MVVM und DataBinding.
Wenn ich jetzt allerdings "wpf search and replace dialog for textbox" in eine Suchmaschine eingebe, dann finde ich jede Menge Codebeispiele, die getestet sind und funktionieren. Da könntest dir also eine Menge Zeit und Frustration sparen, wenn du dir mal anschaust, wie andere Leute das bereits umgesetzt haben.
Bitte beachte [Hinweis] Wie poste ich richtig?
Weeks of programming can save you hours of planning
Stimmt, in dem Fall schon aber das Event bleibt dasselbe Thema, egal ob jetzt bei Textänderung oder per ButtonKlick...
In beiden Fällen könnte ein und dasselbe Event gefeuert und die Suche nach außen angesteuert werden, ohne daß das <Edit2> SubWindow vom MainWindow </Edit2> bescheid weiß... ([Edit2]: war verdreht, das SubWindow sollte vom Main.. nix wissen...)
Somit kannst nämlich auch für andere Fenster die Suche aktivieren, zudem ist es sauber getrennt... mehr oder weniger...
[Edit1]
natürlich ist der Weg den @MrSparkle gerade benannt hat am vernüpftigsten. Damit kann man sich solche Probleme größenteils ersparen. Denn so wie es hier aussieht, wie unter WinForms und nicht WPF...
Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄
Da der TE es nicht schafft einen ScreenShot von der Anzeige zu posten, poste ich mal einen ScreenShot von mir.
Da kann man sehen, dass die Auswahl weiterhin angezeigt wird. (Da wo der rote Pfeil drauf zeigt).
Wenn ich jetzt allerdings "wpf search and replace dialog for textbox" in eine Suchmaschine eingebe, dann finde ich jede Menge Codebeispiele, die getestet sind und funktionieren. Da könntest dir also eine Menge Zeit und Frustration sparen, wenn du dir mal anschaust, wie andere Leute das bereits umgesetzt haben.
Ist nicht so, dass ich nicht gesucht hätte. Bitte dann eins davon posten was tatsächlich funktioniert. Ich habe nämlich keins gefunden. Das meiste davon ist mit RichTextBox oder WinForms umgesetzt.
@ Sir Rufo
ich glaube es macht wenig Sinn wenn ich hier ein Screenshot poste worin kein Text selektiert ist.
Ich habe ja die Situation mit Text genau beschrieben.
Aber hier trotzdem:
Aufruf über Button:
WPF Snippets and Hacks: Correct way to keep selection in TextBox and RichTextBox visible after focus lost in WPF
Hilft dir das?
Edit:
Sorry, habe das hier übersehen:
However, if new window is opened, focus on both controls will be lost.