ich habe jetzt so viel arbeit reingesteckt 🙁
-ueberlegungen waren : datagridcolumnstyle ableiten und selber ein dropdown schreiben
-selber eine art liste mit normalen textboxes usw. machen
-datagrid mit autocompletet textbox verwenden.
da ich das datagrid mag und die anderen dinge mich nicht ueberzeugen konnten, da ich ja auch mit ner datatable arbeite...
nun probiere ich die auto complete eigenschaft der text box einer datagridtextboxcolumn instanz zu veraendern, doch das will nicht klappen. mit den selben einstellungen klappt es bei einem normalen textfeld. eine solche problematik wurde schon von anderen fetsgestellt, dort wurde sie aber nicht geloest, daher mein hilferuf an euch!
vielen dank im vorraus herboive
noobie / Anfänger
C# 8) 8)
Hallo albatros,
vielen Dank für dein Vertrauen auf eine Antwort von mir. Allerdings ist DataGrid mein schacher Punkt. Auch mit Autocomplete habe ich noch nicht gearbeitet. Deshalb musst du wohl auf eine Antwort von jemand anders warten.
herbivore
Hallo albatros.
Finde es anderen Usern gegenüber nicht gut/fair, wenn man direkt einer Person dankt, bevor überhaupt eine Antwort geschrieben wurde.
Natürlich weiß herbivore sehr viel, aber eben auch nicht alles. Ich sehe aber mal darüber weg und versuche dir trotzdem zu helfen.
Im Internet habe ich, wie du oben bereits geschrieben hast nur gefunden, dass die DataGridTextBoxColumn wohl sehr fehlerhaft ist.
Aus diesem Grund habe ich mir mal eine eigene DataGridTextBoxColumn erstellt. Diese ist von DataGridColumnStyle abgeleitet.
public class CustomDataGridTextBoxColumn : DataGridColumnStyle
{
private bool isEditing;
private CustomTextBoxControl textBox = new CustomTextBoxControl();
public CustomDataGridTextBoxColumn()
: base()
{
textBox.Visible = false;
}
public TextBox TextBox
{
get { return this.textBox; }
}
protected override void Abort(int rowNum)
{
isEditing = false;
textBox.TextChanged -= new EventHandler(TextBoxTextChanged);
Invalidate();
}
protected override bool Commit(CurrencyManager dataSource, int rowNum)
{
textBox.Bounds = Rectangle.Empty;
textBox.TextChanged -= new EventHandler(TextBoxTextChanged);
if (!isEditing)
return true;
isEditing = false;
try
{
string value = textBox.Text;
SetColumnValueAtRow(dataSource, rowNum, value);
}
catch (Exception)
{
Abort(rowNum);
return false;
}
Invalidate();
return true;
}
protected override void Edit(CurrencyManager source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly, string displayText, bool cellIsVisible)
{
string value = (string)GetColumnValueAtRow(source, rowNum);
if (cellIsVisible)
{
textBox.Bounds = new Rectangle(
bounds.X + 2, bounds.Y + 2, bounds.Width - 4, bounds.Height - 4);
textBox.Text = value;
textBox.Visible = true;
textBox.TextChanged += new EventHandler(TextBoxTextChanged);
}
else
{
textBox.Text = value;
textBox.Visible = false;
}
if (textBox.Visible)
DataGridTableStyle.DataGrid.Invalidate(bounds);
textBox.Focus();
}
protected override int GetMinimumHeight()
{
return textBox.PreferredHeight + 4;
}
protected override int GetPreferredHeight(System.Drawing.Graphics g, object value)
{
return textBox.PreferredHeight + 4;
}
protected override System.Drawing.Size GetPreferredSize(System.Drawing.Graphics g, object value)
{
return new Size(100, textBox.PreferredHeight + 4);
}
protected override void Paint(Graphics g, Rectangle bounds, CurrencyManager source, int rowNum)
{
Paint(g, bounds, source, rowNum, false);
}
protected override void Paint(Graphics g, Rectangle bounds, CurrencyManager source, int rowNum,
bool alignToRight)
{
Paint(
g, bounds,
source,
rowNum,
Brushes.Red,
Brushes.Blue,
alignToRight);
}
protected override void Paint(Graphics g, Rectangle bounds, CurrencyManager source, int rowNum,
Brush backBrush, Brush foreBrush, bool alignToRight)
{
string value = (string)GetColumnValueAtRow(source, rowNum);
Rectangle rect = bounds;
g.FillRectangle(backBrush, rect);
rect.Offset(0, 2);
rect.Height -= 2;
g.DrawString(value, this.DataGridTableStyle.DataGrid.Font, foreBrush, rect);
}
protected override void SetDataGridInColumn(DataGrid value)
{
base.SetDataGridInColumn(value);
if (textBox.Parent != null)
{
textBox.Parent.Controls.Remove
(textBox);
}
if (value != null)
{
value.Controls.Add(textBox);
}
}
private void TextBoxTextChanged(object sender, EventArgs e)
{
textBox.TextChanged -= new EventHandler(TextBoxTextChanged);
this.isEditing = true;
base.ColumnStartedEditing(textBox);
}
}
Diese Klasse kapselt ein CustomTextBoxContol
public class CustomTextBoxControl : TextBox
{
protected override bool ProcessKeyMessage(ref Message m)
{
return ProcessKeyEventArgs(ref m);
}
}
Angewendet wird die CustomDataGridTextBoxColumn z.B. so:
public class MyForm : Form
{
private DataTable namesDataTable;
private DataGrid grid = new DataGrid();
public MyForm()
: base()
{
InitForm();
namesDataTable = new DataTable("NamesTable");
namesDataTable.Columns.Add(new DataColumn("Name"));
DataColumn dateColumn = new DataColumn
("Value", typeof(string));
dateColumn.DefaultValue = "Default";
namesDataTable.Columns.Add(dateColumn);
DataSet namesDataSet = new DataSet();
namesDataSet.Tables.Add(namesDataTable);
grid.DataSource = namesDataSet;
grid.DataMember = "NamesTable";
AddGridStyle();
AddData();
}
private void AddGridStyle()
{
DataGridTableStyle myGridStyle = new DataGridTableStyle();
myGridStyle.MappingName = "NamesTable";
DataGridTextBoxColumn nameColumnStyle =
new DataGridTextBoxColumn();
nameColumnStyle.MappingName = "Name";
nameColumnStyle.HeaderText = "Name";
myGridStyle.GridColumnStyles.Add(nameColumnStyle);
CustomDataGridTextBoxColumn textBoxColumn = new CustomDataGridTextBoxColumn();
textBoxColumn.MappingName = "Value";
textBoxColumn.HeaderText = "Value";
textBoxColumn.Width = 100;
AutoCompleteStringCollection acs = new AutoCompleteStringCollection();
acs.AddRange(new string[] { "Hallo Welt", "Hallo Nachbar", "Eintracht", "Pyramide" });
textBoxColumn.TextBox.AutoCompleteCustomSource = acs;
textBoxColumn.TextBox.AutoCompleteMode = AutoCompleteMode.Suggest;
textBoxColumn.TextBox.AutoCompleteSource = AutoCompleteSource.CustomSource;
myGridStyle.GridColumnStyles.Add(textBoxColumn);
grid.TableStyles.Add(myGridStyle);
}
private void AddData()
{
DataRow dRow = namesDataTable.NewRow();
dRow["Name"] = "Name 1";
dRow["Value"] = "Value1";
namesDataTable.Rows.Add(dRow);
dRow = namesDataTable.NewRow();
dRow["Name"] = "Name 2";
dRow["Value"] = "Value2";
namesDataTable.Rows.Add(dRow);
dRow = namesDataTable.NewRow();
dRow["Name"] = "Name 3";
dRow["Value"] = "Value3";
namesDataTable.Rows.Add(dRow);
dRow = namesDataTable.NewRow();
dRow["Name"] = "Name 4";
dRow["Value"] = "Value4";
namesDataTable.Rows.Add(dRow);
dRow = namesDataTable.NewRow();
dRow["Name"] = "Name 5";
dRow["Value"] = "Value5";
namesDataTable.Rows.Add(dRow);
namesDataTable.AcceptChanges();
}
private void InitForm()
{
this.Size = new System.Drawing.Size(500, 500);
grid.Size = new System.Drawing.Size(350, 250);
grid.TabStop = true;
grid.TabIndex = 1;
grid.Dock = DockStyle.Fill;
this.StartPosition = FormStartPosition.CenterScreen;
this.Controls.Add(grid);
}
}
In der Form gibt es ein DataGrid mit zwei Columns. Die Column "Value" ist AutoComplete fähig. Versuch es mit den Worten "Hallo Welt", "Hallo Nachbar", "Eintracht", "Pyramide".
Die Eigenschaft
textBox.AutoCompleteMode = AutoCompleteMode.Append;
legt fest, wie dem User die Möglichkeiten angezeigt werden sollen.
Hoffe das hilft.
Gruss
Friedel
Ohne Ziel ist auch der Weg egal.
WOW vielen dank fuer die muehe, sieht schonmal ganz richtig aus soweit...
eine frage ist es moeglich die klasse datagridtextboxcolumn einfach zu ueberschreiben, dait man nichts aendern muss im bisherigen quelltext (rein aestetisch)
sry deswegen, war eher ein scherz - nicht die annahme das er imme alles weiss, tut er ja auch nicht wie wir nun spaetestens wissen 😉
noobie / Anfänger
C# 8) 8)
Finde es eigentlich ästhetischer, ein neues "fehlerfreies" Control zu schreiben, als in einem vorhandenem "falschen" so lange rumzuwurschteln, bis es ungefähr das macht, was ich will. 🙂
Gruss
Friedel
Ohne Ziel ist auch der Weg egal.
nicht rumbasteln, sondern überschreiben!!!
vielen dank auf alle fälle, aber mir cheint als wäre da ein kleiner bug drinne:
wenn ich auf ein feld klicke und anfange zu schreiben, dann schreibt er erst los bei zweiten gedrückten buchstaben, daher:
klick auf ein feld, tastendruck - keine wirkung, tastendurck - jetzt wirkung!
ich habe schon geguckt, w da was fehlt aber bisher nicht gefunden, kann mir jemand helfen?
noobie / Anfänger
C# 8) 8)
Du brauchst doch gar nicht viel im vorhandenen Quellcode ändern, da sowohl die original als auch die neue TextBox von DataGridColumnStyle erbt.
wenn ich auf ein feld klicke und anfange zu schreiben, dann schreibt er erst los bei zweiten gedrückten buchstaben, daher:
bei mir nicht...
Gruss
Friedel
Ohne Ziel ist auch der Weg egal.
mh das ist komisch hast du auch das gleiche verwendet wie hier gepostet wurde oder dir original...
noobie / Anfänger
C# 8) 8)
Habe mit Copy & Paste alles nochmal neu erstellt und wie gesagt, bei mir legt er direkt mit dem ersten Buchstaben los.
Gruss
Friedel
Ohne Ziel ist auch der Weg egal.
argh ich glaub das nicht... kannst du einmal die kompilierte exe und einmal das projekt hier rein packen?
edit: ich denke ich vergas zusätzlich zu erwähnen das die bei einer neuen zeile (*) passiert!!! offensichtlich schreibt er den buchstaben, dann löscht er ihn aber wieder und setzt die zeile vom edit in den exist mode (statt * ein stift) und dann muss man von vorne schreiben! mh komisch oder? vll ist das ja auch bei euch so?
noobie / Anfänger
C# 8) 8)
In einer neuen Zeile habe ich das noch gar nicht probiert (peinlich), aber stimmt dann tritt der Effekt auf.
base.ColumnStartedEditing(textBox);
löst dieses Problem aus. Die Methode ist zwar virtual, aber die zu überschreiben, wird mehr als schwierig, da diese viele Objekte aus dem System.Windows.Forms Namespace nutzt, welche als internal markiert sind.
Als Workaround :
private void TextBoxTextChanged(object sender, EventArgs e)
{
string tempString = textBox.Text; //<<<<<<<
textBox.TextChanged -= new EventHandler(TextBoxTextChanged);
this.isEditing = true;
base.ColumnStartedEditing(textBox);
textBox.Text = tempString; //<<<<<<
textBox.SelectionStart = tempString.Length;
}
entsprechend ändern und der Effekt wird "versteckt".
//edit: "textBox.SelectionStart = tempString.Length;" vergessen.
Gruss
Friedel
Ohne Ziel ist auch der Weg egal.
und ich dachte schon irgentwas stimmt bei mir oder meinem pc nicht!
danke für den Fachrat! ihr seit echt super!
noobie / Anfänger
C# 8) 8)