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;
}
}
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.
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?
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...
Sorry - .NET Framework 4.8.
Ich suche jetzt mal ein paar bmp Bilder und versuche es.
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?
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?
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?
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.
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?