Laden...
K
Benutzerbeschreibung
Infos über mich unter www.stangerweb.de

Forenbeiträge von kstanger Ingesamt 99 Beiträge

18.02.2023 - 17:32 Uhr

Wollte mich ja wieder melden: ich habe es mit einem Timer realisiert.
Sobald der letzte Frame gesendet ist, startet mein Timer.


responseArduino = false;
...
if (isSent)
{
  TimerArduinoResponse = new Timer();
  TimerArduinoResponse.Tick += new EventHandler(TimerArduinoResponse_Tick);
  TimerArduinoResponse.Interval = 2000;
  TimerArduinoResponse.Start();
}

Wenn die Quittung vom Arduino angekommen ist, setze ich ein Flag


responseArduino = true;

Der Timer-Eventhandler informiert den User, wenn das Flag nicht gesetzt wurde


public void TimerArduinoResponse_Tick(object sender, EventArgs e)
{
   TimerArduinoResponse.Stop();
   if (!responseArduino)
   {
      string message = "Bitte prüfen, ob Arduino-Port geöffnet ist";
      const string caption = "Arduino antwortet nicht";
      MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
      return;
    }
}

14.02.2023 - 10:40 Uhr

Danke für eure Hinweise. Ich werde wohl mit dem Timer arbeiten, wie trib es beschrieben hat. PeriodicTimer Class gibt es bei .Net Framework 4.8 noch nicht.
Allerdings wird es etwas dauern, bis ich alles entsprechend umgesetzt habe. Ich melde mich dann wieder.

12.02.2023 - 19:03 Uhr

Hallo,
ich weiß nicht, ob meine Frage hier hin gehört, aber vielleicht doch...
Auf Arduino-Seite, wird durch Serial.begin nach User-Eingabe der Port geöffnet.
Ich sende dann Daten von einem PC (programmiert mit C#) an den Arduino Mega.
Sobald die Daten auf Arduino-Seite empfangen sind, werden sie als Quittung zurückgesendet. (Ich könnte auch eine andere Quittung zurücksenden.)
Wenn der Arduino-Port nicht geöffnet wurde, wird auch nichts zurück gesendet.

Ich will irgendwie erkennen, ob der Port im Arduino geöffnet ist. Ich denke, dass ich per Timeout-Mechanismus nach meinem Senden das erkennen sollte.
Mein Data-Received Handler sieht aktuell so aus und funktioniert auch:


        private void SerialPortArduino_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // Paket = <stx><dle>5 Bytes Daten<etx>
            if (!SerialPortArduino.IsOpen) return;
            if (sync)
            {
                byte[] buffer = new byte[8];
                int bytes = SerialPortArduino.BytesToRead;
                if (bytes > 7)
                {
                    SerialPortArduino.Read(buffer, 0, 8);
                    if (buffer[0] == stx && buffer[1] == dle && buffer[7] == etx)
                    {
                        sync = true;
                        receivedBytes = new byte[8];
                        receivedBytes = buffer;
                        this.Invoke(new EventHandler(ShowData));
                    }
                    else
                    {
                        SerialPortArduino.DiscardInBuffer();
                        sync = false;
                        if (readBuffer.Count > 0) readBuffer = new List<byte>();
                    }
                }
            }
            if (!sync)
            {
                while (SerialPortArduino.BytesToRead > 0)
                {
                    int indata = SerialPortArduino.ReadByte();
                    if (indata == (int)stx && readBuffer.Count == 0)
                    {
                        readBuffer.Add((byte)indata);
                        indata = SerialPortArduino.ReadByte();
                    }
                    else
                    {
                        SerialPortArduino.DiscardInBuffer();
                        sync = false;
                        if (readBuffer.Count > 0) readBuffer = new List<byte>();
                    }
                    if (indata == (int)dle && readBuffer.Count == 1)
                    {
                        readBuffer.Add((byte)indata);
                        indata = SerialPortArduino.ReadByte();
                    }
                    else
                    {
                        SerialPortArduino.DiscardInBuffer();
                        sync = false;
                        if (readBuffer.Count > 0) readBuffer = new List<byte>();
                    }
                    while (readBuffer.Count > 1 && readBuffer.Count < 7)
                    {
                        readBuffer.Add((byte)indata);
                        indata = SerialPortArduino.ReadByte();
                    }
                    if (readBuffer.Count == 7 && indata == (int)etx)
                    {
                        sync = true;
                        readBuffer.Add((byte)indata);
                        receivedBytes = new byte[8];
                        receivedBytes = readBuffer.ToArray();
                        this.Invoke(new EventHandler(ShowData));
                        readBuffer = new List<byte>();
                    }
                    else
                    {
                        sync = false;
                        readBuffer = new List<byte>();
                    }
                }
            }
        }

Wie und an welchen Stellen muss nun eine "Timeout-Abfrage" eingebaut werden?
Gemäß https://learn.microsoft.com/de-de/dotnet/api/system.io.ports.serialport.readtimeout?view=netframework-4.8 (Docs) müsste ich bei jedem Read so etwas einbauen:
(SerialPortArduino.ReadTimeout = 1500; // nur bei der C# Port-Definition)


try
{
    SerialPortArduino.Read(buffer, 0, 8);
// alternativ
    int indata = SerialPortArduino.ReadByte();
}
catch (TimeoutException)
{
    // Ausgabe: Port im Arduino nicht verfügbar
}

Muss ich dann nochmal alle Write-Puffer löschen?

Oder gibt es generell andere Möglichkeiten?

31.01.2023 - 10:36 Uhr

Es funktioniert!
Ich hatte einen saublöden Fehler gemacht: ich hatte die RichTextBox auf Readonly gesetzt, damit kein User da was ändern kann. Damit konnte aber auch nichts vom Clipboard per Code kopiert werden.
Die Lösung ist dann einfach: zuerst das Bild einfügen, dann auf Readonly setzen.

Dein Tipp war aber entscheidend: (oder ist es ausgegraut)

Jetzt kommt der nächste Schritt: das Bild in den Textfluss einbauen...

31.01.2023 - 09:56 Uhr

Sorry - .NET Framework 4.8.
Ich suche jetzt mal ein paar bmp Bilder und versuche es.

31.01.2023 - 09:24 Uhr

Ich verwende .NET Framework 8. Wäre mal interessant, ob es da Unterschiede zu 4 gibt.
Wäre auch interessant, wie du das BMP eingefügt hast. Vielleicht habe ich da einen Fehler?

30.01.2023 - 18:43 Uhr

Sieht so aus, als hätte niemand bisher eine Idee, wie das zu machen ist.
Ich habe inzwischen eine Möglichkeit gefunden, ein Bild in einer RichTextBox darzustellen:


PictureBox NeoPixel = new PictureBox();
NeoPixel.SizeMode = PictureBoxSizeMode.StretchImage;
Bitmap ImageNeoPixel = new Bitmap("NeoPixel.jpg");
NeoPixel.ClientSize = new Size(400,254);
NeoPixel.Image = ImageNeoPixel;
RichTextBoxAufbauanleitung.Controls.Add(NeoPixel);

Damit befindet sich das Bild in der linken oberen Ecke.
Wenn ich jetzt aber einen Text hinzufüge, dann wird der Text hinter das Bild geschrieben, d.h. er startet auch in der linken oberen Ecke.
Wie kann ich die PictureBox an eine beliebige Stelle in der RichTextBox positionieren? Wie kann ich Text um das Bild herumfließen lassen?
Ich glaube zu verstehen, dass durch das Controls.Add die PictureBox genau so ein Kind-Element ist wie der RTF-Text, also parallel zu ihm ist. Ich meine, dass ich die PictureBox nicht an die RichtTextBox, sondern an den RTF-Text anbinden muss.
Wie kann man das machen?

20.01.2023 - 19:09 Uhr

Hallo,

Ich habe in Word eine RTF-Datei mit einem Bild erstellt und wollte dieses in einer RichTextBox darstellen. Die RichtTextBox ignoriert das Bild und stellt nur den Text dar.
Ich habe den Artikel "Insert Plain Text and Images into RichTextBox at Runtime" gelesen, wollte es aber erst einmal mit dem Clipboard versuchen:


Clipboard.SetImage(Image.FromFile("NeoPixel.jpg"));
DataFormats.Format myFormat = DataFormats.GetFormat(DataFormats.Bitmap);
if (RichTextBoxAufbauanleitung.CanPaste(myFormat))
{
      RichTextBoxAufbauanleitung.Paste(myFormat);
}
else
{
      MessageBox.Show("Datenformat funktioniert nicht.");
}

Dachte ich, das mag vielleicht am jpg-Format liegen; habe also das Bild in eine Bitmap umgewandelt. Aber auch mit NeoPixel.bmp funktioniert es nicht.
Es ist immer die Paste-Methode die nicht funktioniert.

Hat jemand eine Idee, was da falsch ist?

30.12.2022 - 11:14 Uhr

Das war genau der richtige Tipp! Ich habe das jetzt so programmiert und noch ein e.Cancel eingefügt, damit die Zelle nicht verlassen wird.


        private void DataGridViewFarbe_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (DataGridViewFarbe.Columns[e.ColumnIndex] == DataGridViewFarbe.Columns["Farbname"])
            {
                string patternFarbname = @"^[a-zäöüA-ZÄÖÜ0-9](( |-)?[a-zßäöüA-ZÄÖÜ0-9])*$";
                MatchCollection match = Regex.Matches(e.FormattedValue.ToString(), patternFarbname);
                if (match.Count > 0)
                {
                    return;
                }
                else
                {
                    MessageBox.Show("Fehler: #" + e.FormattedValue.ToString() + "# nicht erlaubt");
                    e.Cancel = true;
                    return;
                }
            }
            return;
        }

Vielen Dank für die Hilfe.

29.12.2022 - 19:20 Uhr

Hallo,

ich habe ein DGV, in dem ich per Programmierung eine neue Zeile einfüge. (DGV ist gebunden per BindingSource, die wiederum mit einer Liste von Objekten verbunden ist.) Ich stelle dabei sicher, dass in der Zeile nur gültige Daten sind. Der User soll aber die Daten ändern, zumindest einen Namen. Dieser Name darf nur alphanumerische Zeichen, Umlaute, ß und Leerzeichen oder Bindestrich enthalten, sofern diese von den alphanumerischen Zeichen "umrahmt" sind. Die Prüfung dazu führe ich per Regex mit einem entsprechenden Pattern durch. All dies funktioniert soweit.
Wenn der User etwas ändert, dann ist er in der entsprechenden Zelle im Editiermodus. Sobald er die Zelle verlassen will, soll das nur erlaubt sein, wenn seine Änderung die o.g. Forderung erfüllt. Ich habe dazu den CellValidating-Handler bemüht; das funktioniert aber nicht richtig. Der User muss quasi die Zelle verlassen. dann nochmal aufrufen und erst dann beim Verlassen wird die Meldung angezeigt.


        private void DataGridViewFarbe_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (DataGridViewFarbe.Columns[e.ColumnIndex] == DataGridViewFarbe.Columns["Farbname"])
            {
                string patternFarbname = @"^[a-zäöüA-ZÄÖÜ0-9](( |-)?[a-zßäöüA-ZÄÖÜ0-9])*$";
                MatchCollection match = Regex.Matches(DataGridViewFarbe.CurrentCell.Value.ToString(), patternFarbname);
                if (match.Count > 0)
                {
                    return;
                }
                else
                {
                    MessageBox.Show("Fehler: #" + DataGridViewFarbe.CurrentCell.Value.ToString() + "# nicht erlaubt");
                    return;
                }
            }
            return;
        }

Fragen:
Welcher Handler oder Kombination von Handlern ist hier angebracht?

27.12.2022 - 17:13 Uhr

Danke für den Tipp - funktioniert prima!

27.12.2022 - 12:28 Uhr

Hallo,

ich stelle eine RGB-Farbinformation in einer TextBox als Hintergrundfarbe dar. Um die Farbe (es sind meist helle Farben) besser vom Hintergrund abzusetzen, wollte ich einen dunkelgrauen dicken Rahmen (10 Pixel) um das Rechteck haben. Ich habe aber für die Textbox keine Eigenschaft "Rahmen" gefunden; meine Einstellung ist Borderstyle=Fixed3D. Daher habe ich die Textbox in eine GroupBox (ohne Schrift) mit grauer Hintergrundfarbe getan. Jetzt sehe ich, dass die GroupBox unten und oben je eine helle Linie hat.
Die Einstellungen der GroupBox sind
BackColor: Gray
BackgroundImage: (keine)
BackgroundImageLayout: Tile
FlatStyle: Flat
ForeColor: ControlText
Margin: 0;0;0;0
Padding: 0;0;0;0
Enabled: False

  1. Gibt es eine Rahmen-Eigenschaft für Textboxen? (Dann brauche ich keine GroupBox)
  2. Kann man die GroupBox ohne die störenden Linien erzeugen?

Mit Weihnachtlichen Grüßen
Karl

01.12.2022 - 10:58 Uhr

@Th69:
In der Doku zu SortableBindingList steht:

This content has been retired and may not be updated in the future. The product, service, or technology mentioned in this content is no longer supported.

Also werde ich doch die zugrunde liegende Liste Timings sortieren, es sei denn jemand, der die Grundlagen so richtig versteht (z.B. FZelle), bringt mir die richtige Liste, mit der das dann alles kein Problem ist.

30.11.2022 - 13:28 Uhr

-> TH69: das mit den Texten bei Switch werde ich ändern.

-> TH69: BindingSourceTiming.DataSource = new BindingList<Timing>(Timings); ergibt "not supported"

-> FZelle: falsche Liste - welche Liste soll ich denn nehmen?
ich brauche doch eine IBindingList, oder?
Das haben wir diskutiert und festgestellt, dass es nicht (?) geht.
https://mycsharp.de/forum/threads/124985/verstaendnisprobleme-mit-bindinglist

Also bleibt die Frage, wie das gehen soll, wenn ich die richtige Liste nicht nehmen kann. Dazu brauche ich einen Vorschlag; sonst bleibt mir doch nur das BubbleSort. 😠

30.11.2022 - 11:30 Uhr

Das habe ich mir auch schon überlegt, so als Plan B.
Danke, dass du es hier schon dargestellt hast, spart mir etwas Aufwand.

Andererseits ist es ein schwaches Bild von den UI-Entwicklern, ein DataGridView zu entwickeln (was ja an Excel erinnern soll) und dort die Funktionalität des Sortierens (was ich als Basic sehe) so zu machen, dass sie eigentlich nicht in das Gesamtkonzept passt und daher nur mit großer Mühe (wenn überhaupt) zu programmieren ist.

30.11.2022 - 09:06 Uhr

-> BerndFfm: nein, not supported

-> david.m: ja, aber da kann ich nur eine BindingList erzeugen, und das gibt auch not supported
So habe ich es nochmal verifiziert:


            BindingList<Timing> source = new BindingList<Timing>(Timings);
            BindingSourceTiming.DataSource = source;
            if (BindingSourceTiming.SupportsSorting != true)
            {
                MessageBox.Show(" no SupportsSorting");  // ergibt no SupportsSorting
            }

29.11.2022 - 18:06 Uhr

Hallo,
Nichts scheint hier einfach zu gehen. 🙁
Ich wollte das DataGridView sortieren: geht aber nur, wenn nicht gebunden.
-> ok ->
Dann versuche ich es mal mit der BindingSource:


        private void ComboBoxTimingSortieren_SelectedIndexChanged(object sender, EventArgs e)
        {
            BindingSourceTiming.DataSource = Timings;
            if (BindingSourceTiming.SupportsSorting != true)
            {
                MessageBox.Show(" no SupportsSorting");
            }
            switch (ComboBoxTimingSortieren.SelectedItem.ToString())
            {
                case "Uhrzeit, Led und Relais gemischt":
                    BindingSourceTiming.Sort = "Uhrzeit ASC";
                    break;
                case "Uhrzeit Led, dann Uhrzeit Relais":
                    BindingSourceTiming.Sort = "Typ ASC, Uhrzeit ASC";
                    break;
                case "Uhrzeit Relais, dann Uhrzeit Led":
                    BindingSourceTiming.Sort = "Typ DESC, Uhrzeit ASC";
                    break;
                case "Led Uhrzeit, dann Relais Uhrzeit":
                    BindingSourceTiming.Sort = "Uhrzeit ASC, Typ ASC";
                    break;
                case "Relais Uhrzeit, dann Led Uhrzeit":
                    BindingSourceTiming.Sort = "Uhrzeit ASC, Typ DESC";
                    break;
                 default:
                    BindingSourceTiming.Sort = "Uhrzeit ASC";
                    break;
            }
        }

Geht auch nicht, da das nicht supported wird. Dazu muss die "zugrunde liegende Liste eine IBindingList sein.
Meine zugrunde liegende Liste ist mit


public List<Timing> Timings; 

definiert.
Wie komme ich denn jetzt zu einer IBindingList?

28.11.2022 - 19:21 Uhr

Ich habe soeben einen Teilerfolg erzielt:
Im DragDrop habe ich nach dem BindingSourceTiming.EndEdit() nochmal die DataSource neu gesetzt:


BindingSourceTiming.EndEdit();
BindingSourceTiming.DataSource = Timings;

Damit ist zuerst einmal der Fehler weg. Da dieses neue Setzen der DataSource immer passieren soll, habe ich das wieder gelöscht und als ersten Befehl in die DataBindingComplete gesetzt:


private void DataGridViewTiming_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
    BindingSourceTiming.DataSource = Timings;
    ...

Der Erfolg ist nur ein Teilerfolg, weil jetzt die Linq-Sequenzen nicht mehr funktionieren: Das Query wird dadurch einfach überschrieben. Also muss ich mir für das Sortieren etwas anderes einfallen lassen.

Ich bitte um Kommentare, ob ich da auf dem richtigen Weg bin.

28.11.2022 - 18:20 Uhr

Da hast du Recht - ist Blödsinn. Habe ich entfernt.
Aber der Fehler bleibt unverändert.

Ich habe auch noch gesehen, dass sich, wenn 2 Comboboxen unterschiedlichen Inhalts durch den User vertauscht werden, die Liste der Objekte nicht ändert.

27.11.2022 - 18:50 Uhr

Hallo,
kurz bevor mich die Verzweiflung vollständig packt frage ich hier um Hilfe.
In meinem DataGridView (DGV) stelle ich Daten dar, die zeilenweise aus unterschiedlichen ComboBoxen (und damit unterschiedlichen Listen von Objekten stammen. Bei 2 User-Aktionen wird eine Spalte nicht aktualisiert, die Entsprechende ComboBox auch nicht und einzelne Zellen bleiben leer. Ich sehe 2 Aktionen, durch das dies beeinflusst wird:

  • Drag & Drop: der User packt eine Zeile und verschiebt sie
  • Sortieren: die Zeilen werden ebenfalls verschoben
    Das Ganze passiert nur dann, wenn eine ComboBox mit einer anderen unterschiedlichen Inhalts vertauscht wird.
    3 Methoden tragen möglicherweise dazu bei:
    DataBindingComplete

        private void DataGridViewTiming_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            for (int loop = 0; loop < Timings.Count; loop++)
            {
                DataGridViewComboBoxCell cbCellNumBesch = (DataGridViewComboBoxCell)DataGridViewTiming.Rows[loop].Cells[3];
                DataGridViewComboBoxCell cbCellNummer = (DataGridViewComboBoxCell)DataGridViewTiming.Rows[loop].Cells[2];
                if (Timings[loop].Typ == Lichtquelle.Relais)
                {
                    if (cbCellNumBesch != null)
                    {
                        cbCellNumBesch.DataSource = BindingSourceRelais;
                        cbCellNumBesch.DisplayMember = "RelaisNumBesch";
                        cbCellNumBesch.ValueMember = "RelaisNumBesch";
                    }
                    if (cbCellNummer != null)
                    {
                        cbCellNummer.DataSource = BindingSourceRelais;
                        cbCellNummer.DisplayMember = "RelaisNummer";
                        cbCellNummer.ValueMember = "RelaisNummer";
                    }
                }
                else
                {
                    if (cbCellNumBesch != null)
                    {
                        cbCellNumBesch.DataSource = BindingSourceLed;
                        cbCellNumBesch.DisplayMember = "LedNumBesch";
                        cbCellNumBesch.ValueMember = "LedNumBesch";
                    }
                    if (cbCellNummer != null)
                    {
                        cbCellNummer.DataSource = BindingSourceLed;
                        cbCellNummer.DisplayMember = "LedNummer";
                        cbCellNummer.ValueMember = "LedNummer";
                    }
                }
                DataGridViewTiming.DataSource = BindingSourceTiming;
            }
        }

und DragDrop


        private void DataGridViewTiming_DragDrop(object sender, DragEventArgs e)
        {
            Point clientPoint = DataGridViewTiming.PointToClient(new Point(e.X, e.Y));
            rowIndexOfItemUnderMouseToDropTiming = DataGridViewTiming.HitTest(clientPoint.X, clientPoint.Y).RowIndex;
            if (e.Effect == DragDropEffects.Move)
            {
                rowIndexFromMouseDownTiming = BindingSourceTiming.Position;
                BindingSourceTiming.Insert(rowIndexOfItemUnderMouseToDropTiming, BindingSourceTiming.Current);
                if (rowIndexFromMouseDownTiming > rowIndexOfItemUnderMouseToDropTiming)
                {
                    BindingSourceTiming.RemoveAt(rowIndexFromMouseDownTiming + 1);
                    BindingSourceTiming.Position = rowIndexOfItemUnderMouseToDropTiming;
                }
                else
                {
                    BindingSourceTiming.RemoveAt(rowIndexFromMouseDownTiming);
                    BindingSourceTiming.Position = rowIndexOfItemUnderMouseToDropTiming - 1;
                }
                BindingSourceTiming.EndEdit();
            }
        }


und dann noch SelectedIndexChanged bei einer ComboBox, die nicht im DGV ist:


        private void ComboBoxTimingSortieren_SelectedIndexChanged(object sender, EventArgs e)
        {
            IEnumerable<Timing> timingsortierungQuery;
            switch (ComboBoxTimingSortieren.SelectedItem.ToString())
            {
                case "Uhrzeit, Led und Relais gemischt":
                    timingsortierungQuery =
                        from tq in Timings
                        orderby tq.Uhrzeit ascending
                        select tq;
                    break;
                case "Uhrzeit Led, dann Uhrzeit Relais":
                    timingsortierungQuery =
                        from tq in Timings
                        orderby tq.Typ ascending
                        orderby tq.Uhrzeit ascending
                        select tq;
                    break;
                case "Uhrzeit Relais, dann Uhrzeit Led":
                    timingsortierungQuery =
                        from tq in Timings
                        orderby tq.Typ descending
                        orderby tq.Uhrzeit ascending
                        select tq;
                    break;
                case "Led Uhrzeit, dann Relais Uhrzeit":
                    timingsortierungQuery =
                        from tq in Timings
                        orderby tq.Uhrzeit ascending
                        orderby tq.Typ ascending
                        select tq;
                    break;
                case "Relais Uhrzeit, dann Led Uhrzeit":
                    timingsortierungQuery =
                        from tq in Timings
                        orderby tq.Uhrzeit ascending
                        orderby tq.Typ descending
                        select tq;
                    break;
                default:
                    timingsortierungQuery =
                        from tq in Timings
                        orderby tq.Uhrzeit ascending
                        select tq;
                    break;
            }
            BindingSourceTiming.DataSource = timingsortierungQuery.ToList();
        }

In meiner Verzweiflung habe ich einen Button erzeugt, der mir die DGV-Werte per MessageBox darstellt.


        private void ButtonDGVInhalt_Click(object sender, EventArgs e)
        {
            for (int loop = 0; loop< Timings.Count; loop++)
            {
                MessageBox.Show(DataGridViewTiming.Rows[loop].Cells["Uhrzeit"].Value + ", "
                    + DataGridViewTiming.Rows[loop].Cells["Typ"].Value + ", "
                    + DataGridViewTiming.Rows[loop].Cells["Nummer"].Value.ToString() + ", "
                    + DataGridViewTiming.Rows[loop].Cells["NumBesch"].Value + ", "
                    + DataGridViewTiming.Rows[loop].Cells["Zustand"].Value);
            }
        }


Und dort werden alle Daten richtig angezeigt.
Jetzt weiß ich nicht mehr weiter und bitte um Hilfe.

24.11.2022 - 12:14 Uhr

Ich habe es gefunden:


       private void DataGridViewTiming_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if (DataGridViewTiming.IsCurrentCellDirty)
            {
                DataGridViewTiming.CommitEdit(DataGridViewDataErrorContexts.Commit);
            }
        }


Dadurch wird das CellValueChanged-Ereignis ausgelöst.

24.11.2022 - 12:05 Uhr

Hallo,
ich habe eine DataGridViewComboBox. Wenn der User den Wert ändert nutze ich das CellValueChaged-Ereignis, um andere Inhalte zu ändern. Das funktioniert auch. Die Änderung kommt aber erst, wenn eine andere Zelle angeklickt wird.
Welches Ereignis kann man nutzen, um die Änderung zu starten, wenn der geänderte Wert in der ComboBox angezeigt wird?

23.11.2022 - 12:25 Uhr

Ich habe gelesen, dass ein DataError auftritt, wenn z.B. Daten von einem Speicher geladen werden und dabei ein Fehler entsteht. Entweder muss dann der Zellenwert korrigiert werden oder die Formatierung muss geändert werden.
Da ja alles richtig angezeigt wird, schließe ich einen Datenfehler aus und vermute einen Formatierungsfehler. Ich habe bisher keinen Formatfehler gefunden und nun folgenden Code geschrieben:


        private void DataGridViewTiming_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            if (e.Exception.Message == "Der DataGridViewComboBoxCell-Wert ist ungültig.")
            {
                object value = DataGridViewTiming.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
                if (!((DataGridViewComboBoxColumn)DataGridViewTiming.Columns[e.ColumnIndex]).Items.Contains(value))
                {
                    ((DataGridViewComboBoxColumn)DataGridViewTiming.Columns[e.ColumnIndex]).Items.Add(value);
                }
            }
        }

Wirklich zufrieden bin ich damit aber nicht.
Hat jemand eine Idee, wo und wie ich suchen könnte?

22.11.2022 - 18:54 Uhr

Hallo,

Ich will eine im DataGridView eine ComboBox zeilenweise in Abhängigkeit von Werten in einer anderen Spalte füllen. Dazu habe ich bei Form_Load die Liste von Objekten eingelesen und die BindingSource festgelegt.


           Timings = inOut.ReadTiming(Timings, Presettings);
            BindingSourceTiming.DataSource = Timings;
...
            DataGridViewTiming.Columns[2].Name = "Nummer";
            DataGridViewTiming.Columns[3].Name = "NumBesch";
...
            DataGridViewTiming.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(DataGridViewTiming_DataBindingComplete);

Im Designer habe ich die Columns 2 und 3 als DataGridViewComboBoxColumn festgelegt.
Schließlich rufe ich das DataBindingComplete-Event auf, wo ich die ComboBoxen zeilenweise befülle. Damit überschreibe ich die Einstellung der Column 3.


        private void DataGridViewTiming_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            for (int loop = 0; loop < Timings.Count; loop++)
            {
                DataGridViewComboBoxCell cbCell = (DataGridViewComboBoxCell)DataGridViewTiming.Rows[loop].Cells["NumBesch"];
                if (Timings[loop].Typ == Lichtquelle.Relais)
                {
                    Timings[loop].Nummer = Relaises[Timings[loop].Nummer].RelaisNummer;
                    Timings[loop].NumBesch = Relaises[Timings[loop].Nummer].RelaisNumBesch;
                    if (cbCell != null)
                    {
                        cbCell.DataSource = BindingSourceRelais;
                        cbCell.DisplayMember = "RelaisNumBesch";
                        cbCell.ValueMember = "RelaisNummer";
                    }
                }
                else
                {
                    Timings[loop].Nummer = Leds[Timings[loop].Nummer].LedNummer;
                    Timings[loop].NumBesch = Leds[Timings[loop].Nummer].LedNumBesch;
                    if (cbCell != null)
                    {
                        cbCell.DataSource = BindingSourceLed;
                        cbCell.DisplayMember = "LedNumBesch";
                        cbCell.ValueMember = "LedNummer";
                    }
                }
            }
        }

Ich erhalte dann den Fehler> Fehlermeldung:

System.FormatException: Der DataGridViewComboBoxCell-Wert ist ungültig.

Wenn ich dann das DataError-Ereignis bediene, und zwar mit einer leeren Methode


        private void DataGridViewTiming_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
        }

erhalte ich das gewünschte Ergebnis, d.h. mein DGV ist so gefüllt wie ich es möchte.
Trotzdem muss es einen Fehler bei der ComboBoxCell geben. Kann mir da jemand helfen?

21.11.2022 - 10:51 Uhr

Irgendwie müsste doch das erste join mit dem ersten where gruppiert werden, und das zweite join mit dem zweiten where. Würde das zweite where sich auf das erste join beziehen, wäre das Ergebnis falsch.

21.11.2022 - 09:39 Uhr

Ich habe das mal ausprobiert


IBindingList<Timing> source = new BindingList<Timing>(Timings);

und bekomme die Fehlermeldung> Fehlermeldung:

Typ "IBindingList" ist nicht generisch und kann daher nicht mit Typargumenten verwendet werden.


BindingList<Timing> source = new BindingList<Timing>(Timings);

gibt keine Fehlermeldung und funktioniert.

20.11.2022 - 18:32 Uhr

Danke für die Erklärung. Hat mir viel zum Verständnis von <T> geholfen. Funktioniert mit


IBindingList source = new BindingList<Timing>(Timings);

20.11.2022 - 14:29 Uhr

Das dachte ich auch, aber mit


IBindingList source = new BindingList<T>(Timings);

gibt es einen Fehler für Timings:> Fehlermeldung:

Konvertierung von "System.Collections.Generic.List<Ledsteuerung5.Timing>" in "System.Collections.Generic.IList<T>" nicht möglich.

Außerdem gibt es noch einen Fehler für T:> Fehlermeldung:

Der Typ- oder Namespacename "T" wurde nicht gefunden (möglicherweise fehlt eine using-Directive oder ein Assemblyverweis).


using System.ComponentModel;
using System.Collection.Generic;

sind vorhanden.

20.11.2022 - 11:28 Uhr

Hallo,
obwohl ich die Doku mehrfach rauf und runter gelesen habe, verstehe ich nicht, was eine BindingList ist und wie sie aufgerufen wird.
Ich habe ein Objekt mit diversen Membern.


public class Timing
{
... Konstruktoren
}

Damit erzeuge ich eine Liste von Objekten


public List<Timing> Timings;

Nun sollte die BindingList eine Alternative zur BindingSource sein, wobei die BindingList wohl eine Teilmenge der BindingSource ist.
Was ist dann mit einem Code


IBindingList source = new BindingList<T>(datasource);

Was ist dann datasource in meinem Fall? Ich bin da komplett verwirrt.
Kann mir jemand das erklären?

18.11.2022 - 20:01 Uhr

Ich wollte das mit einer Linq-Abfrage lösen, aber folgender Code funktioniert nicht:


            var timingQuery =
                from tq in Timings
                join lq in Leds on tq.Nummer equals lq.Nummer
                where tq.Typ.Equals(Lichtquelle.Led)
                join rq in Relaises on tq.Nummer equals rq.Nummer
                where tq.Typ.Equals(Lichtquelle.Relais)
                select tq;
            BindingSourceTiming.DataSource = timingQuery.ToList();

Geht das überhaupt mit Linq?

18.11.2022 - 18:57 Uhr

Danke!
Irgendwie habe ich da auf dem Schlauch gestanden.

18.11.2022 - 14:39 Uhr

Mein Code funktioniert nicht:


    public class Timing
    {
        private string _uhrzeit;

        public Timing()
        {
        }

        public Timing(int tagminute, Lichtquelle typ, int nummer, BZustand zustand)
        {
            Tagminute = tagminute;
            Typ = typ;
            Nummer = nummer;
            Zustand = zustand;
        }

        public int Tagminute
        {
            get => UhrzeitToTotalmin(_uhrzeit);
            set => _uhrzeit = TotalminToUhrzeit(value);
        }
        public Lichtquelle Typ { get; set; }
        public int Nummer { get; set; }
        public BZustand Zustand { get; set; }
    }

Die Spalte im DGV habe ich so definiert:


            DataGridViewTextBoxColumn dgvTextUhrzeit = new DataGridViewTextBoxColumn()
            {
                HeaderText = "Uhrzeit",
                DataPropertyName = "Tagminute",
            };

Was mache ich da falsch?

18.11.2022 - 11:45 Uhr

Hallo,
ich habe eine Liste von Objekten, die ich in einem DataGridView (DGV) darstelle. Ich möchte aber in einer Spalte einen berechneten Wert darstellen. Mir ist klar, dass DGV nur darstellt und nicht berechnet. Irgendwo auf dem Weg vom Objekt über die BindingSource muss eine Methode mit dem Berechnungsalgorithmus sein. Ich weiß nicht, wo ich das machen muss.
Kann mir jemand sagen, wie das geht oder wo das dokumentiert ist? Ich dachte, es würde mit Linq gehen, aber da habe ich nicht gefunden wie man eine Methode dort einbaut.

17.11.2022 - 10:34 Uhr

Hallo,
ich möchte ein DataGridView (DGV) spaltenweise initialisieren. Dazu habe ich ein DGV DataGridViewTiming im Designer leer ohne Bindung erstellt.
In der Methode Form1 lege ich die einzelnen Spalten fest:


            DataGridViewTextBoxColumn dgvTextUhrzeit = new DataGridViewTextBoxColumn();
            //dgvTextUhrzeit.DataSource = BindingSourceTiming;      // das funktioniert nicht - hier weiß ich nicht, wie ich die Spalte an eine BindingSource anbinden soll
            dgvTextUhrzeit.HeaderText = "Uhrzeit";
            dgvTextUhrzeit.DataPropertyName = "Uhrzeit";
            DataGridViewTiming.Columns.Add(dgvTextUhrzeit);

            DataGridViewComboBoxColumn dgvComboTyp = new DataGridViewComboBoxColumn();
            dgvComboTyp.DataSource = BindingSourceTiming;
            dgvComboTyp.HeaderText = "Lichtquelle";
            dgvComboTyp.DataPropertyName = "Typ";
            dgvComboTyp.DisplayMember = "Typ";
            dgvComboTyp.ValueMember = "Typ";
            DataGridViewTiming.Columns.Add(dgvComboTyp);

            DataGridViewComboBoxColumn dgvComboNummer = new DataGridViewComboBoxColumn();
            dgvComboNummer.DataSource = BindingSourceTiming;
            dgvComboNummer.HeaderText = "Nr.";
            dgvComboNummer.DataPropertyName = "Nummer";
            dgvComboTyp.DisplayMember = "Nummer";
            dgvComboTyp.ValueMember = "Nummer";
            DataGridViewTiming.Columns.Add(dgvComboNummer);

            DataGridViewComboBoxColumn dgvComboBeschreibung = new DataGridViewComboBoxColumn();
            dgvComboBeschreibung.DataSource = BindingSourceTiming;
            dgvComboBeschreibung.HeaderText = "Beschreibung";
            dgvComboBeschreibung.DataPropertyName = "Beschreibung";
            dgvComboBeschreibung.DisplayMember = "Beschreibung";
            dgvComboBeschreibung.ValueMember = "Nummer";
            DataGridViewTiming.Columns.Add(dgvComboBeschreibung);

            DataGridViewComboBoxColumn dgvComboZustand = new DataGridViewComboBoxColumn();
            dgvComboZustand.DataSource = BindingSourceTiming;
            dgvComboZustand.HeaderText = "Zustand";
            dgvComboZustand.DataPropertyName = "Zustand";
            DataGridViewTiming.Columns.Add(dgvComboZustand);

Mein Objekt hat u.a. folgenden Inhalt:


        public string Uhrzeit { get; set; }
        public Lichtquelle Typ { get; set; }
        public int Nummer { get; set; }
        public string Beschreibung { get; set; }
        public BZustand Zustand { get; set; }

Dabei sind Lichtquelle und BZustand


   public enum Lichtquelle
    {
        Led,
        Relais
    };

    public enum BZustand
    {
        ein,
        aus
    };


In Form1_Load lade ich die Liste der Objekte (Timings = List<Timing>) und lege die Bindung der BindingSource an das Objekt fest.


            Timings = inOut.ReadTiming(Timings, Presettings);    // diese Methode funktioniert richtig, habe sie aber hier nicht dargestellt
            BindingSourceTiming.DataSource = Timings;

Im DGV werden die Werte nicht angezeigt. Was ist falsch?

16.11.2022 - 13:10 Uhr

Ich versuche eine andere Erklärung:
mein DGV hat 5 Spalten. In der Spalte 2 können nur die Werte "Liste1" oder "Liste 2" stehen. In der Spalte 3 steht eine ComboBox. Diese hat für jede Zeile entweder die Werte der Liste 1 oder die Werte der Liste 2. Und zwar gilt folgendes:

  • wenn Spalte 2 Wert = "Liste 1", dann stehen in der ComboBox in Spalte 3 die Werte der Liste 1
  • wenn Spalte 2 Wert = "Liste 2", dann stehen in der ComboBox in Spalte 3 die Werte der Liste 2
    Ich hoffe, das macht die Sache etwas klarer.
14.11.2022 - 17:54 Uhr

Hallo,

ich habe ein DataGridView (DGV), welches über eine BindingSource an eine Liste von Objekten angebunden ist. In dem DGV habe ich eine Spalte mit Comboboxen die alternativ an eine Liste von Objekten1 oder an eine Liste von Objekten 2 angebunden ist. In einer weiteren Spalte habe ich ein Enum mit den Werten Liste1 und Liste 2. Wenn der User in einer Zelle dieser Spalte Liste 1 auswählt, soll die Combobox mit der Liste von Objekten 1 in dieser Zeile angebunden werden. Wenn der User in einer anderen Zelle Liste 2 auswählt, soll die Combobox mit der Liste von Objekten 2 in dieser Zeile angebunden werden.
Wie programmiert man so etwas?
Als Idee habe ich:

  • ComboBoxen zur Laufzeit definieren.
  • Per Eventhandler in der Enum-Zelle die entsprechende Combobox auswählen
08.11.2022 - 18:17 Uhr

Hallo,
um einem 3-Schichten-Modell gerecht zu werden, habe ich eine Methode zu "Daten einlesen" in einer gesonderten Klasse InOut ausgelagert. In meiner Form rufe ich diese Methode auf:


private void FormLedsteuerung_Load(object sender, EventArgs e)
{
    InOut.ReadPresettings();
... weiterer Code

Da die Methode aber Nicht-Statisch ist, funktioniert das nicht. Ich brauche einen Objektverweis.


private void FormLedsteuerung_Load(object sender, EventArgs e, InOut inOut)
{
     inOut.ReadPresettings();
... weiterer Code

Dann bekomme ich aber den Fehler> Fehlermeldung:

Keine Überladung für "FormLedsteuerung_Load" stimmt mit dem Delegaten "EventHandler" überein.

Wie kann ich den Objektverweis anders erzeugen?

06.11.2022 - 17:09 Uhr

Aaah - hatte ich nicht registriert.
Danke für die Info - wieder was gelernt.

06.11.2022 - 15:21 Uhr

Hallo allerseits,
ich habe ein DataGridView DGV, welches an eine BindingSource angebunden ist.
In diesem DGV möchte ich die Methode ClearSelection anwenden.


DGV.ClearSelection();

funktioniert.


DGV.ClearSelection(myRow, myColumn, true);

funktioniert nicht:> Fehlermeldung:

Keine Überladung für die ClearSelection-Methode nimmt 3 Argumente an.

In der Doku ist diese Methode aber so beschrieben.
Ich verstehe das nicht.

20.10.2022 - 13:52 Uhr

Kann ich die im Projekt erzeugen?
z.B. Wenn Datenbank nicht vorhanden, dann erzeuge sie und fülle sie mit Startwerten.

20.10.2022 - 13:46 Uhr

-> gfoidl

  • Den Artikel kenne ich schon länger; deswegen habe ich auch die Bezeichnungen der Schichten genauso gewählt.
  • Serialiserung nehme ich, weil es ein sehr kleines Projekt ist. Wenn ich eine Datenbank nehmen würde, dann müsste ich z.B. die Datenbank auch mit auf einen anderen Rechner übertragen, oder?
19.10.2022 - 11:47 Uhr

Ich habe Fragen zum 3-Schichten-Modell:
Wie trennt man eigentlich die 3 Schichten? z.B. über unterschiedlichen Namespaces?
Und wie verbindet man sie? z.B. über Methodenaufrufe?

Irgendwie habe ich das Gefühl, dass man gerne über das Modell spricht, nicht aber über die Umsetzung. Was ich bisher gefunden habe, sind Aussagen "Das Projekt ist zu groß, als dass man es hier zeigen kann". Einfache Beispiele habe ich bisher nicht gefunden.

Bei meinem Anwendungsbeispiel wäre
Datenzugriffsschicht = Definition der Objektlisten + Serialisierung
Präsentations-Schicht = Definition von DGV, Combo, Buttons usw. einschließlich Eigenschaften und Eventhandler-Aufrufe
Logikschicht = Durchführung der Eventhandler, rechnen, und alles, was sonst noch übrig ist.

17.10.2022 - 13:58 Uhr

Hallo,

ich habe jetzt ein Datenmodell erstellt und wollte zuerst einmal wissen, ob das richtig ist und ob ich auf dem richtigen Weg bin.
Zuerst habe ich meine Klasse Farbe mit einer abgeleiteten Klasse erweitert.


    public class FarbeErweitert : Farbe
    {
        public FarbeErweitert()
        {
        }

        public FarbeErweitert(int red, int green, int blue, string farbname, bool markierung) : base(red, green, blue, farbname)
        {
            Markierung = markierung;
        }
        public bool Markierung { get; set; }
    }


Dann habe ich eine Liste FarbeErweiterts erzeugt


List<FarbeErweitert> FarbeErweiterts = new List<FarbeErweitert>();

und dieser dann die Werte aus der Liste Farben zugewiesen und die Markierung entsprechend gesetzt.


            for (loopFarben = 0; loopFarben < Farben.Count; loopFarben++)
            {
                FarbeErweitert xxx = new FarbeErweitert(Farben[loopFarben].Red, Farben[loopFarben].Green, Farben[loopFarben].Blue, Farben[loopFarben].Farbname, false);
                FarbeErweiterts.Add(xxx);
                bool used = false;
                for (loopLeds = 0; loopLeds < Leds.Count; loopLeds++)
                {
                    if (Leds[loopLeds].Ledfarbname == Farben[loopFarben].Farbname) {
                        used = true;
                        break;
                    }
                }
                if (used)
                {
                    FarbeErweiterts[loopFarben].Markierung = true;
                 }
              }

Ist das bis dahin richtig?

16.10.2022 - 09:39 Uhr

Hallo Wilfried,

vielen Dank für deine Lösung. Ich habe es noch nicht ausprobiert.
Ich habe sofort nachgeschaut, warum ich das nicht herausgefunden habe, obwohl ich die Tipps hatte, insbesondere die von T-Virus.

  • Bei deiner Zeile 2 wusste ich nicht, dass man das gewünschte Format bei ToString angeben kann. Ich dachte, das wäre immer ToString(). Lerneffekt: Jetzt verstehe ich, dass ToString() das Default-Ergebnis liefert und dass man bei Angabe des gewünschten Formats eben dieses als Ergebnis hat.
  • Bei deiner 3. Zeile wusste ich nicht, dass ich die TotalMinutes-Eigenschaft anhängen muss. Hier habe ich eben nicht alles gelesen, was es zu TimeSpan gibt. Lerneffekt: ich muss nicht nur entweder die Methoden oder Eigenschaften ansehen, sondern alles und im Zusammenhang verstehen.

Ich hoffe, dass ich das jetzt so richtig verstanden habe. Weiterhin hoffe ich, dass ich zukünftig ein besseres Verständnis zur Doku entwickle.
Vielen Dank für eure Hilfe und auch eure Kritik an meiner Vorgehensweise.

15.10.2022 - 20:51 Uhr

Wenn ihr sagt, dass es mit TimeSpan oder DateTime funktioniert, dann zeigt mir bitte doch die Lösung!
Was ich brauche, ist ganz einfach:

  • Minuten als int im Gültigkeitsbereich von 0 bis 1439 sollen umgewandelt werden in einen String im Format "hh:mm".
  • Und umgekehrt.
14.10.2022 - 19:13 Uhr

Ich weiß, dass alles dokumentiert ist. Ich lese auch die Dokumentation, aber ich verstehe nicht alles. Bitte bedenkt, dass ihr etliche Jahre Wissensvorsprung gegenüber mir habt. Wenn ich z.B. nur einmal die TimeSpan-Doku lese, dann bedeutet das nicht, dass ich auch alles verstehe. Und alle 5 Worte ist ein Verweis auf irgend etwas, von dem ich nicht weiß, ob es sehr wichtig, wichtig oder eben nur nice to know ist. Von DataGridView, BindingSource, usw. weiß ich seit ein paar Wochen, dass es das gibt. Bitte verzeiht mir, dass ich das nicht alles verstehe.

Andererseits habe ich mich früher mal mit Regulären Ausdrücken beschäftigt: heute ist es für mich "einfach", einen Regex-String zu verstehen. Genau so mit Datumsformaten: in der Vergangenheit habe ich damit gekämpft, dass User sehr gerne ihre "eigenen" Datumsformate benutzt haben. Das hat dazu geführt, dass ich die (Culture-Spezifischen) alle kennenlernte und letzendlich den Usern einen Kalender zu anklicken gegeben habe, so dass sie gezwungen waren, diesen und nur diesen zu benutzen. Das Datum mit Uhrzeit habe ich dann als Unix-Timestamp intern benutzt.

Trotzdem bin ich bereit, eure Expertise anzunehmen und auch zu nutzen - ich bin euch sehr dankbar, dass ihr mir überhaupt helft. Und entschuldigt bitte, dass ich hier so rumjammere - aber das musste jetzt mal raus.

Wenn ihr alle Zeit der Welt habt und auch die Lust dazu, dann kann mir ja mal jemand ein Code-Snippet erzeugen, mit dem man das, was ich da verbrochen habe, besser und C#-modern darstellt.

14.10.2022 - 15:29 Uhr

Hallo,
ich habe inzwischen einiges gelesen und vielleicht auch etwas davon gelernt. Ich komme aber trotzdem nicht weiter. Mein letzter Stand ist eine Änderung im Aufruf:


DataGridViewRow row = DataGridViewFarben.Rows[loopFarben];
row.DefaultCellStyle.Font = new Font(DataGridViewFarben.Font, FontStyle.Bold);

Es funktioniert aber trotzdem nicht, und zwar (wie ich meine) aus folgendem Grund: Microsoft schreibt

Das CellFormatting Ereignis tritt jedes Mal auf, wenn jede Zelle gezeichnet wird, sodass Sie bei der Behandlung dieses Ereignisses eine lange Verarbeitung vermeiden sollten. Dieses Ereignis tritt auch auf, wenn die Zelle FormattedValue abgerufen wird oder die GetFormattedValue Methode aufgerufen wird.

Was muss ich denn jetzt tun? Die Formatierung muss ja auch ohne Eingriff des Users in diese DGV passieren, z.B. wenn in dem anderen DGV eine Änderung erfolgt.

14.10.2022 - 11:12 Uhr

Hallo,
mit TimeSpan funktioniert die eine Richtung sehr gut, aber die andere Richtung ist problematisch. Ich habe es daher selbst programmiert und im folgenden Beispiel demonstriert:


using System;
using System.Text.RegularExpressions;

namespace Demo_Uhrzeit_MinutenProTag
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string pattern = @"^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$";
            string uhrzeit;
            int totalmin;
            int stunden;
            int minuten;

            // Anzahl der Minuten pro Tag in Uhrzeit (hh:mm) umwandeln
            Console.Write("Total Minuten: ");
            totalmin = int.Parse(Console.ReadLine());
            if (totalmin < 0 || totalmin > 1439)
            {
                Console.WriteLine("Fehler: Anzahl Minuten nicht im Bereich eines Tages (0 - 1439)");
            }
            else
            {
                stunden = totalmin / 60;
                minuten = totalmin % 60;
                uhrzeit = stunden.ToString("D2") + ":" + minuten.ToString("D2");
                Console.WriteLine("Uhrzeit = " + uhrzeit);
            }
            Console.WriteLine();

            // Uhrzeit in Anzahl der Minuten pro Tag umwandeln
            Console.Write("neue Uhrzeit: ");
            uhrzeit = Console.ReadLine();
            MatchCollection match = Regex.Matches(uhrzeit, pattern);
            if (match.Count > 0)
            {
                int position = uhrzeit.IndexOf(":");
                stunden = int.Parse(uhrzeit.Substring(0, position));
                minuten = int.Parse(uhrzeit.Substring(position + 1));
                totalmin = stunden * 60 + minuten;
                Console.WriteLine("Total Minuten: " + totalmin.ToString());
            }
            else
            {
                Console.WriteLine("Fehler: Format falsch oder Uhrzeit größer 23:59");
            }
            Console.ReadLine();
        }
    }
}


13.10.2022 - 17:18 Uhr

Hallo allerseits,

ich möchte eine Uhrzeit im Format HH:mm darstellen und dabei mit Minuten rechnen. Es geht mir dabei nicht um eine Uhrzeit, die mit einem Datum verknüpft ist und mit der intern mit Ticks gerechnet wird. Ich möchte ausschließlich Minuten. Gibt es so etwas oder muss ich mir das selbst basteln?
Als Alternative könnte ich mir noch vorstellen, dass ich mit Sekunden rechne, aber nur HH:mm darstelle. Ich arbeite mit .Net4.8, so dass Timeonly nicht in Frage kommt.

11.10.2022 - 19:20 Uhr

Ich habe das mit Style ausprobiert --- funktioniert leider auch nicht.
Das Beispiel aus deinem Link habe ich auch ausprobiert: es ändert die Farbe in der gesamten Spalte. Ich dachte, es würde dann mit Rows genau so gehen - leider gibt es kei CellTemplate für Rows.