Autor Beitrag
Määx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Do 27.06.13 15:54 
Hallo zusammen,

ich habe einige Textboxen in denen ich die standard AutoComplete-Funktion nutze. Nun möchte ich diese gern an 2 Stellen erweitern:
Zum einen würde ich gerne einen Autocomplete für Textteile haben. Ich habe also zum Beispiel den Wert "Hallo Herr xyz". Beim tippen von "Herr" sollte dann der Textvorschlag kommen.
Zum anderen möchte ich in einer anderen Textbox Multiline aktivieren und bei jedem Wort die Autocomplete-Funktion nutzen. Also quasi Textbausteine einführen.

Gibt es hier bereits fertige Funktionen, die ich noch nicht gefunden habe oder müsste man sich das selber schreiben? Falls es selbst gemacht werden muss, wie packe ich das Ganze am besten an?

Vielen Dank für eure Hilfe
Määx
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4795
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 27.06.13 19:36 
Hallo Määx,

das mußt du auf jeden Fall selber schreiben, da der Standard AutoComplete-Modus nur den Wortanfang (Prefix) beachtet.
Hier ein paar Links (mit Code) dazu:
email-autocomplete
AutoComplete Suggest Box
Create an AutoComplete TextBox Control in C#

Und bei der MultiLine-TextBox müßtest du dann an aktueller Position die ListBox (bzw. DropDownBox) anzeigen.
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Do 25.07.13 10:20 
Hey,

erstmal vielen Dank für die Links - die haben mir schonmal sehr geholfen. Leider funktioniert das ganze noch nciht so wie gewünscht:
Der erste Link bietet leider keine SourceCode an, so dass ich diesen nicht nutzen kann (will das selber machen, damit ich auch alles verstehe was da passiert). Der letzte wählt im Prinzip das erste passende Element aus und legt es direkt in die Textbox. Der mittlere macht zwar genau das, was ich will, aber das Textfeld verliert beim öffnen des ToolStripDropDown-Menüs den Focus. Das bedeutet, ich tippe einen Buchstaben und der springt sofort in die ListBox. Einen zweiten Buchstaben kann ich nicht eingeben ohne vorher wieder in das Textfeld zu klciken. Ich möchte jedoch wie beim normalen AutoComplete tippen können bis ich die Listbox auf eine übersichtliche Anzahl an Elementen reduziert habe bzw. wenn das gesuchte Element nicht vorhanden ist einfach weiter tippen bis die Box verschwindet.

Leider bekomme ich das einfach nicht hin. Ich habe this.Focus() bzw. base.Focus() am Ende der OnTextChanged probiert. Auch habe ich dem Opened&GotFocus-Events des toolStrips das Setzen des Fokusses hinzugefügt. Aber egal was ich mache, das TextFeld verliert den Focus und man kann nicht weiter tippen.

Wie kann ich das Problem lösen?
Vielen vielen Dank
Määx
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4795
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 25.07.13 11:13 
Hallo Määx,

hast du denn mal den boolschen Rückgabewert von Focus überprüft?
Oder probiere mal
ausblenden C#-Quelltext
1:
ActiveControl = this;					

bzw.
ausblenden C#-Quelltext
1:
Select()					

aus.

Edit: Ich habe es gerade mal selber ausprobiert und es scheint nicht so einfach zu sein, denn anscheinend kann man, während das ToolStripDropDown (oder der ToolStripControlHost) aktiv ist, nicht einfach den Tastaturfokus ändern.
Selbst ein
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
Form form = FindForm();
if (form != null)
{
  form.ActiveControl = null;
  form.ActiveControl = this;
}

zeigt zwar den Cursor (in der TextBox) an, aber tippen kann man trotzdem nicht. :(
Erst mit Drücken der "Esc"-Taste kommt man wieder aktiv in die TextBox zurück.
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Do 25.07.13 17:21 
Hey,

genau das habe ich auch festgestellt. Meine this.Focus() gab immer true zurück und wenn ich den Focus in der gotFocus der anderen Elemente setze bekam ich ebenfalls den Cursor im Textfeld, nicht aber die Möglichkeit der Tastatureingabe. Erst nach erneutem klick ins Textfeld oder Esc ging dies. Gleichzeitig vercshwindet dann aber auch das ToolStripDropDown. Das ist ja ebenfalls nicht erwünscht :(

Hat jemand eine Idee wie ich das sonst realisieren könnte? habe schon überlegt ein extra UserControll zu nehmen in dem eine TextBox und eine ListBox sind. Die Größe des Controlls müsste ich dann immer anpassen (oder immer eine Delegate remove/addListBox(ListBox listBox, Point position) anlegen) aber irgendwie gefällt mir diese Lösung nicht wirklich und es muss doch eine elegantere Variante geben?

Vielen Dank für eure Hilfe!!
Määx
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Do 25.07.13 18:00 
Hey

Ich habe mal ein wenig rumgespielt. Ich habe die Autpvervollständigung über ne zweite (Rich)TextBox gemacht. Bei Rich kannste nämlich die gleichen Elemente noch Fett machen oder hervorheben.
Die RichTextBox wandert mit dem Cursor in der TextBox und zeigt immer eine Liste der möglichen Pharsen an. Die Liste wird aus einer List<string> genommen.
Als Form hab ich mal ne einfache Form mit einer TextBox genommen.

Probier mal n bissl rum. Mach ich auch noch nacher wenn ich wieder Zeit hab ;)

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DropDownTest
{
  public partial class Form1 : Form
  {
    private RichTextBox boxAutoComplete;
    private Graphics measureGraphics, autoCompleteMeasureGraphics;

    private readonly char[] wordSeperator = {' ''\n''\r'};
    private List<string> autoCompleteList = new List<string>
    {
      "Hallo Herr so und so",
      "Guten Tag Frau Blau",
      "Mein Name ist",
      "Ich wohne in",
      "Ich bin 2 Jahr alt"
    };

    public Form1()
    {
      InitializeComponent();
      boxAutoComplete = new RichTextBox {Visible = false, WordWrap = false};

      boxAutoComplete.TextChanged += AutoCompleteBoxTextChanged;
      Controls.Add(boxAutoComplete);

      boxAutoComplete.BringToFront();
      measureGraphics = boxText.CreateGraphics();
      autoCompleteMeasureGraphics = boxAutoComplete.CreateGraphics();

    }

    private void boxText_TextChanged(object sender, EventArgs e)
    {
      string word = GetLastWord();

      if (boxAutoComplete.Visible)
      {
        SizeF size = measureGraphics.MeasureString(boxText.Lines[boxText.Lines.Length - 1], boxText.Font);
        Point location = new Point((int) size.Width, (int) (boxText.Lines.Length * boxText.Font.SizeInPoints));    // Get location of the last char
        location = PointToClient(boxText.PointToScreen(location));                          // Get location in Form coorinates
        boxAutoComplete.Location = location;
      }

      string[] possiblePhrases = autoCompleteList.Where(s => s.Contains(word)).ToArray();

      if (possiblePhrases.Length == 0)
      {
        boxAutoComplete.Visible = false;    // No auto complete possible
      }

      boxAutoComplete.Lines = possiblePhrases;
      boxAutoComplete.Select(0, boxAutoComplete.Lines[0].Length);      // Pre select a line -> insert the Text on ENTER or s.e.
      boxAutoComplete.Visible = true;
    }

    private void AutoCompleteBoxTextChanged(object sender, EventArgs e)
    {
      if (boxAutoComplete.Lines.Length == 0return;

      string longest = "";
      foreach (string line in boxAutoComplete.Lines) if (line.Length > longest.Length) longest = line;  // Get longest line in its width
      
      boxAutoComplete.Width = (int)Math.Round(autoCompleteMeasureGraphics.MeasureString(longest, boxAutoComplete.Font).Width + 0.4f);
    }

    private string GetLastWord()
    {
      string s = "";
      for (int i = boxText.TextLength - 1; i >= 0; i--)
      {
        if (wordSeperator.Any(c => c == boxText.Text[i]) && !String.IsNullOrEmpty(s)) break// check for word seperators
        s = boxText.Text[i] + s; // add in reversed order
      }

      return s;
    }
  }
}

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Fr 26.07.13 09:22 
klasse, vielen Dank!
Ich werde mal damit rumspielen und mich hier noch ienmal melden!
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Fr 26.07.13 15:43 
Hey,

also vom Grundprinzip klappt das so. Ich habe jetzt die richTextBox durch eine ListBox ersetzt und mit etwas mühe könnte man sicherlich quasi die AutoComplete Funktionalität erzielen...
Aber jetzt habe ich das Problem, dass ich das ja in jedem UserControll neu erstellen müsste, da ich ja die ListBox immer anlegen muss...

Hier meine modifizierte Version:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
private ListBox listBoxAutoComplete;
private Graphics measureGraphics, autoCompleteMeasureGraphics;

private readonly char[] wordSeperator = { ' ''\n''\r' };
private List<string> autoCompleteList = new List<string>
{
      "Hallo Herr so und so,",
      "Guten Tag Frau Blau",
      "Mein Name ist",
      "Ich wohne in",
      "Ich bin 2 Jahr alt"
};

public Form1()
{
   InitializeComponent();

   listBoxAutoComplete = new ListBox { Visible = false };
   listBoxAutoComplete.KeyDown += AutoCompleteBoxKeyDown;
   Controls.Add(listBoxAutoComplete);

   listBoxAutoComplete.BringToFront();
   measureGraphics = boxText.CreateGraphics();
   autoCompleteMeasureGraphics = listBoxAutoComplete.CreateGraphics();
}

        private void AutoCompleteBoxKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                listBoxAutoComplete.Visible=false;
                boxText.Focus();
                return;
            }

            if (e.KeyCode == Keys.Enter)
            {
                boxText.Text += listBoxAutoComplete.SelectedItem.ToString();
                boxText.Focus();
                return;
            }
        }
        private void boxText_TextChanged(object sender, EventArgs e)
        {
            if (!boxText.Text.Trim().Equals(""))
            {
                listBoxAutoComplete.Items.Clear();
                string word = GetLastWord();

                if (listBoxAutoComplete.Visible)
                {
                    SizeF size = measureGraphics.MeasureString(boxText.Lines[boxText.Lines.Length - 1], boxText.Font);
                    Point location = new Point((int)size.Width, (int)(boxText.Lines.Length * boxText.Font.SizeInPoints));    // Get location of the last char
                    location = PointToClient(boxText.PointToScreen(location));                          // Get location in Form coorinates
                    listBoxAutoComplete.Location = location;
                }

                string[] possiblePhrases = autoCompleteList.Where(s => s.ToLower().Contains(word.ToLower())).ToArray();

                if (possiblePhrases.Length == 0)
                {
                    listBoxAutoComplete.Visible = false;
                    return;
                }
                foreach (string s in possiblePhrases)
                    listBoxAutoComplete.Items.Add(s);
                listBoxAutoComplete.Visible = true;
            }
            else
                listBoxAutoComplete.Visible = false;
        }
        private string GetLastWord()
        {
            string s = "";
            for (int i = boxText.TextLength - 1; i >= 0; i--)
            {
                if (wordSeperator.Any(c => c == boxText.Text[i]) && !String.IsNullOrEmpty(s)) break// check for word seperators
                s = boxText.Text[i] + s; // add in reversed order
            }

            return s;
        }
        private void boxText_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up)
            {
                if (listBoxAutoComplete.Visible)
                {
                    listBoxAutoComplete.SetSelected(0true);
                    e.SuppressKeyPress = true;
                    listBoxAutoComplete.Focus();
                }
            }
        }


Gibt es eine Möglichkeit das Ganze jetzt irgendwie als CustomAutocompleteTextBox zu verpacken, damt ich es überall schnell&infach nutzen kann?
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 26.07.13 16:27 
Wenn ich dich richtig verstanden habe, meinst du ein custom control.

Hier mal ein Beispiel (hab jetzt nicht alles übernommen):
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DropDownTest
{
  public class AutoCompleteBox : ListBox          // oder halt : RichTextBox oder : TextBox
  {
    public List<string> AutoCompleteList { get; set; }
    public List<char> WordSeperator { get; set; }

    public new bool AutoSize { get; set; }          // Das kannste dann in den graphics mit einbeziehen

    /// <summary>
    /// The TextBox where the AutoCompleteBox should get active.
    /// </summary>
    public TextBoxBase BasedTextBox
    {
      get
      {
        return basedTextBox;
      }
      set
      {
        basedTextBox = value;
        value.KeyDown += OnAnyKeyDown;
      }
    }

    private TextBoxBase basedTextBox;

    public AutoCompleteBox()
    {
      Initialize();
    }

    public AutoCompleteBox(TextBoxBase textBox)
    {
      Initialize();
      BasedTextBox = textBox;
    }

    private void Initialize()
    {
      AutoCompleteList = new List<string>();
      WordSeperator = new List<char>();

      KeyDown += OnAnyKeyDown;
    }

    private void OnAnyKeyDown(object sender, KeyEventArgs e)    // Wird auch beim Tastendruck der entsprechenden TextBox ausgelöst!
    {
      if (Visible)
      {
        if (e.KeyCode == Keys.Down && SelectedIndex > 0)
        {
          SelectedIndex++;
          e.SuppressKeyPress = false;
        }
        else if (e.KeyCode == Keys.Up && SelectedIndex < Items.Count - 1)
        {
          SelectedIndex--;
          e.SuppressKeyPress = false;
        }

        else if (e.KeyCode == Keys.Escape) Hide();
        else if (e.KeyCode == Keys.Enter)
        {
          basedTextBox.Text = basedTextBox.Text.Insert(0, (string)SelectedItem);    // Hier musst du noch die Position zum einfügen ermitteln. 
        }
        
      }
    }

    public new void Show()
    {
      Visible = true;
    }

    public new void Hide()
    {
      Visible = false;
    }
  }
}


/// Nachtrag
So kannst du nach dem ersten Build auch das Control im GUI Editor von Visual Studio nutzen (ich glaube unter Eigene Controls). Dann kannste das Teil einfach auf dein Design drauf ziehen.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Di 30.07.13 08:42 
Super! Funktioniert insgesamt genau so wie ich es mir vorgestellt habe - vor allem kann man so vorhandene Textfelder einfach um diese Funktionalität ergänzen :)
Das einzige "Problem" ist, dass man bei Textfeldern, die in einem UserControl ganz untenangeordnet sind die ListBox nicht mehr angezeigt bekommt, da sie ja über die Grenze des UserControls rausragt...
Gibt es hier eine Möglichkeit so eine Art globales bringToFront() aufzurufen?

Vielen Dank für eure hilfreichen Tipps!!
Määx
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Di 30.07.13 11:54 
Ja genau deswegen hab ich das mit PointToScreen() und PointToClient() gemacht. So kannst du nämlich die ListBox direkt der Form unterordnen. Die Position wird trotz allem passend ausgerechnet und es kann über die Grenzen des Textfeldes angezeigt werden.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Do 01.08.13 16:16 
Hey,

also ich habe jetzt alles ausprobiert. Auch mit dem PointToClient. Aber bei dem PointToClient wird das Feld genauso an den Grenzen des UserControls abgeschnitten, da die angezeigte ListBox ja diesem zugeordnet ist und nicht dem "höchsten" Element. Außerdem springt bei dem PointToClient die Box immer zwischen den beiden Positionen über/unter der aktuellen Zeile hin und her!
Also irgendwas mache ich da falsch - auch wenn mir absolut nicht klar ist was?
Hier meine entsprechende Codestelle:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
public new void Show()
        {
            if (!basedTextBox.Text.Trim().Equals(""))
            {
                SizeF size = graphicsTextBox.MeasureString(basedTextBox.Lines[basedTextBox.Lines.Length - 1], basedTextBox.Font);
                Point location = new Point((int)size.Width, (int)(basedTextBox.Lines.Length * basedTextBox.Font.SizeInPoints));
                //location = new Point(basedTextBox.Location.X + location.X, basedTextBox.Location.Y + location.Y);
                location = PointToClient(basedTextBox.PointToScreen(location));
                Location = location;
                Visible = true;
            }
            else
                Hide();
        }


und hier noch im ganzen:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
public partial class AutoCompleteBox : ListBox
    {
        private Graphics graphicsTextBox;
        public List<string> AutoCompleteList { get; set; }
        private readonly char[] WordSeperator = { ' ''\n''\r' };

        public new bool AutoSize { get; set; }  //not used up to now

        private TextBoxBase basedTextBox;
        /// <summary>
        /// The TextBox where the AutoCompleteBox should get active.
        /// </summary>
        public TextBoxBase BasedTextBox
        {
            get
            {
                return basedTextBox;
            }
            set
            {
                basedTextBox = value;
                graphicsTextBox = value.CreateGraphics();
                value.KeyDown += OnAnyKeyDown;
                value.Click += new EventHandler((sender, arg) => Hide());
            }
        }
                
        public AutoCompleteBox()
        {
            Initialize();
        }
        public AutoCompleteBox(TextBoxBase textBox)
        {
            Initialize();
            BasedTextBox = textBox;
        }
        private void Initialize()
        {
            Visible = false;
            AutoCompleteList = new List<string>();
            KeyDown += OnAnyKeyDown;
        }

        private void OnAnyKeyDown(object sender, KeyEventArgs e)
        {
            string word = GetLastTypedWord();
            if (word.Length > 0)
            {
                if (e.KeyCode != Keys.Down && e.KeyCode != Keys.Up && e.KeyCode != Keys.Enter && e.KeyCode != Keys.Escape)
                {
                    Items.Clear();
                    string[] possiblePhrases = AutoCompleteList.Where(s => s.ToLower().Contains(word.ToLower())).ToArray();

                    if (possiblePhrases.Length == 0)
                    {
                        Hide();
                        return;
                    }
                    string longestLine = "";
                    foreach (string s in possiblePhrases)
                    {
                        Items.Add(s);
                        if (s.Length > longestLine.Length) longestLine = s;      
                    }
                    Width = (int)Math.Round((CreateGraphics()).MeasureString(longestLine, Font).Width + 0.4f);
                    Show();
                }

                if (Visible && Items.Count > 0)
                {
                    if (e.KeyCode == Keys.Down)
                    {
                        if (SelectedIndex < Items.Count - 1)
                            SelectedIndex++;
                        else
                            SelectedIndex = 0;
                        e.SuppressKeyPress = true;
                    }
                    else if (e.KeyCode == Keys.Up)
                    {
                        if (SelectedIndex > 0)
                            SelectedIndex--;
                        else
                            SelectedIndex = Items.Count - 1;
                        e.SuppressKeyPress = true;
                    }
                    else if (e.KeyCode == Keys.Escape) Hide();
                    else if (e.KeyCode == Keys.Enter && SelectedItem != null)
                    {
                        int selectionStatIndex = basedTextBox.SelectionStart - word.Length;
                        basedTextBox.Text = basedTextBox.Text.Remove(selectionStatIndex, word.Length);
                        basedTextBox.Text = basedTextBox.Text.Insert(selectionStatIndex, (string)SelectedItem);
                        basedTextBox.SelectionStart = selectionStatIndex + ((string)SelectedItem).Length;
                        e.SuppressKeyPress = true;
                        Hide();
                    }
                }
            }
            else
                Hide();
        }
        private string GetLastTypedWord()
        {
            string s = "";
            for (int i = basedTextBox.SelectionStart - 1; i >= 0; i--)
            {
                if (WordSeperator.Any(c => c == basedTextBox.Text[i]) && !String.IsNullOrEmpty(s)) break;
                s = basedTextBox.Text[i] + s;
            }
            return s;
        }

        public new void Show()
        {
            if (!basedTextBox.Text.Trim().Equals(""))
            {
                SizeF size = graphicsTextBox.MeasureString(basedTextBox.Lines[basedTextBox.Lines.Length - 1], basedTextBox.Font);
                Point location = new Point((int)size.Width, (int)(basedTextBox.Lines.Length * basedTextBox.Font.SizeInPoints));
                //location = new Point(basedTextBox.Location.X + location.X, basedTextBox.Location.Y + location.Y);
                location = PointToClient(basedTextBox.PointToScreen(location));
                Location = location;
                Visible = true;
            }
            else
                Hide();
        }
        public new void Hide()
        {
            Visible = false;
        }
    }

Hab ihr noch eine Idee?
Vielen Dank
Määx

Edit: achso, die ListBox wird an den Grenzen des UserControls abgeschnitten in dem die TextBox liegt, nicht an den Grenzen der TextBox. Nicht dass da ein Mißverständnis vorlag?
Vielen Dank!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4795
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 01.08.13 16:28 
Hallo Määx,

du solltest dann die ListBox eher der Form (FindForm()) zuordnen (macht aber nur Sinn, wenn die Form auch größer ist als das UserControl).
Ansonsten kannst du es auch versuchen, es dem globalen Screen (Desktop) zuzuordnen, aber dies geht m.E. nur per WinAPI-Funktion SetParent.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 01.08.13 16:31 
Oder die Listbox gleich in eine eigene Form (Borderless) packen.
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Do 01.08.13 17:11 
Zitat:
Oder die Listbox gleich in eine eigene Form (Borderless) packen.

Das klingt am besten :) Aber wie? Also wenn ich in meinem CustomControl eine Form erzeuge und der TextBox zuordne liegt die Form ja wieder nur in dem UserControl oder?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 01.08.13 18:01 
Nö. Ich würde die AutoCompleteBox Klasse einfach nicht von ListBox ableiten. Sondern die Klasse enthält einfach eine Form mit einer Listbox drauf.
Das sollten gefühlt nur ein paar einfache Überarbeitungen der AutoCompleteBox Klasse sein.
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Do 01.08.13 18:06 
Ja das mit dem Springen ist mir auch aufgefallen. Weis aber nicht woran das liegt...

Kurz geschrieben (den restlichen Code musste hald einfügen mittels copy & paste ;)
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
using System;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Windows.Forms;

namespace DropDownTest
{
  internal class AutoCompleteForm : Form
  {
    public List<string> AutoCompleteList { get; set; }
    public List<char> WordSeperator { get; set; }

    public new bool AutoSize { get; set; }

    /// <summary>
    /// The TextBox where the AutoCompleteBox should get active.
    /// </summary>
    public TextBoxBase BasedTextBox
    {
      get
      {
        return basedTextBox;
      }
      set
      {
        if (basedTextBox != null)    // Remove old events
        {
          basedTextBox.KeyDown -= OnAnyKeyDown;
          basedTextBox.TextChanged -= OnBaseBoxTextChanged;
        }

        basedTextBox = value;
        basedTextBox.KeyDown += OnAnyKeyDown;
        basedTextBox.TextChanged += OnBaseBoxTextChanged;

        baseGraphics = basedTextBox.CreateGraphics();
      }
    }


    private ListBox box;
    private TextBoxBase basedTextBox;
    private Graphics baseGraphics, myGraphics;

    public AutoCompleteForm()
    {
      FormBorderStyle = FormBorderStyle.None;
      SizeGripStyle = SizeGripStyle.Show;
      MinimumSize = new Size(1010);
      MaximumSize = new Size(100100);
      

      box = new ListBox {Dock = DockStyle.Fill};
      Controls.Add(box);
    }

    private void OnBaseBoxTextChanged(object sender, EventArgs e)
    {
    }

    private void OnAnyKeyDown(object sender, KeyEventArgs e)
    {
    }
  }
}

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Fr 02.08.13 08:37 
Hallo zusammen,

erstmal Danke für eure schnelle Hilfe! Aber leider glaube ich dass ich irgendetwas grundlegendes nicht verstanden habe :(
Ich habe das nun in eine Form gepackt und es waren tatsächlich nur wenige Änderungen.
Dann habe ich dem UserControl eine private AutoCompleteForm autocompleteForm; hinzugefügt, die ich dann im Konstruktor des Controls initialisiere:
ausblenden C#-Quelltext
1:
autocompleteForm = new AutoCompleteForm(textBoxAnschreiben);					

Wenn ich jetzt etwas im Textfeld eingebe wird auch direkt die Form angezeigt - so weit so gut. Aber leider bekommt diese auch sofort den Focus, so dass ich ja nicht mehr weiter tippen kann? Setze ich den Focus jetzt wieder auf die TextBox verschwindet die Form logischerwese im Hintergrund... gibt es da einen Trick oder müsste ich in der KeyDown "einfach" alles an die TextBox anhängen?

Vielen Dank!
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 02.08.13 09:42 
Beim anzeigen der AutoCompleteForm solltest du einen Parent mitgeben (z.B. die Form auf der die Textbox liegt) damit die AutoCompleteForm immer davor angezeigt wird.
Das mit dem Focus habe ich nicht bedacht das sollte mit ein wenig Bastelei aber auch möglich sein. Der Anfang wäre in der AutoCompleteForm die ShowWithoutActivation Property zu überschreiben und da immer true zurückzugeben.
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Fr 02.08.13 12:23 
oder du benutzt TopMost um die Form einfach im Vordergrund zu halten. Wenn die Applikation den Fokus verliert solltest du TopMost wieder zurücksetzen, damit andere Programme fokussiert werden können.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler