13. oktober 2009 - 22:36Der er
18 kommentarer og 1 løsning
Datagridview opdatere ikke
Jeg har et datagridview med tilhørende datatable som datasource der ikke opdatere efter addning af datarow. Data kommer fra vægt ved at sende command til vægt og afvente at eventen "private void DataRecieved(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)" kører. Alt vedrørende comportkommunikation er lagt i en selvstændig klasse, som sender data til datatable.
Imidlertid sker der ikke nogen synlig opdatering i datagridview'et før at jeg gennemtvinger et repaint af formen( som køres fra en commandbuttom)
Eventen "private void dataGridView1_RowsAdded", som ligger i formen, kører heller ikke.
Tror ikke at din datagridview selv kan fange at der sker ændringer bag om ryggen på den.
Du kunne evt. kalde Refresh på datagridviewet når du tilføjer en række til den datatable som er datasource, så slipper du for at have en knap til at opdatere.
Hvis du vil prøve koden kan du gøre en af to ting:
1) Åbn en Visual Studio command prompt. Gem koden i en fil (f.eks. TestForm.cs) I din VS command prompt skriv: "csc TestForm.cs" Nu har du en TestForm.exe du kan køre.
2) Lav et nyt winforms projekt i visual studio. Slet filerne Form1.cs og Program.cs Lav en ny klasse (TestForm) og kopier koden ind. Hit F5
Men som sagt - lad os se noget af din kode - måske er det bare en eller anden dødsyg fodfejl.
Programmet skal hente data fra 5 vægte via 5 comporte. Programmet fejler ved opstart, hvis disse ikke findes. Analysen hedder Ksat derfor klassen KsatClass som er tænkt som en slags controller. Data lægges tilføjes en datatable som er source i til et datagridview. Data skulle visualiseres ved zedgrafer ved at eventeren rowadded kører. Datatable datagridview og zedgraph er knyttet sammen i klassen zedview hvor eventene også oprettes: ---------------------------------------------------------------------------------------------------------------------------------------------
using System; using ZedGraph; using System.Data; using System.Windows.Forms; using System.Drawing;
this.dgw.RowsAdded += new System.Windows.Forms.DataGridViewRowsAddedEventHandler(dgw_RowsAdded); this.dgw.RowsRemoved += new System.Windows.Forms.DataGridViewRowsRemovedEventHandler(dgw_RowsRemoved);
} public DataTable dataTable { get { return dt; } }
public DataGridView dataGridView { get { return dgw; } }
public ZedGraphControl zedGraphControl { get { return zgc; } }
private void dgw_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e) { try { list.RemoveAt(e.RowIndex); zgc.AxisChange(); zgc.Invalidate(); } catch { } } private void dgw_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) { try { int x = Convert.ToInt32(dt.Rows[e.RowIndex][0]); int y = Convert.ToInt32(dt.Rows[e.RowIndex][2]); list.Add(x, y); zgc.AxisChange(); zgc.Invalidate();
} catch { } } public void AddRow(string fak1,string fak2,string fak3,string fak4) { int t= dt.Columns.Count;
Klassen der snakker med comportene kommer her (vægtene er af mærket Sartorius, derfor navnet): using System; using System.Collections.Generic; using System.Text; using System.IO.Ports; using System.Windows.Forms; using System.Text.RegularExpressions;
this.f = f; } public KsatClass Ksat //hvilken port sender ? { set { ksat = value; } }
private void DataRecieved(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { try { //get portnumber //the portnumber is used in 'getCollectedData()' to know to which grid to //send the data string portName = ((SerialPort)sender).PortName.ToString(); //portNbr = Convert.ToInt32(portName.Substring(portName.Length - 1)); string dataOut="";
//add the last reading to data which i treated in 'getCollectedData() when timer t elabses data += port.ReadExisting(); if(data.Contains("\r\n")) { string[] dataArr = Regex.Split(data, "\r\n"); int i = dataArr.Length - 1; bool found = false; while(i > -1 && found ==false) { string tmp = dataArr[i]; int l =tmp.Length; if (tmp.Length > 11) { found = true;
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using ZedGraph;
Endelig formen: --------------------------------------------------------------------------------------------------------------------------------------------- using System; using System.Data; using System.Drawing; using System.IO.Ports; using System.Text; using System.Windows.Forms;
namespace Ksat { public partial class FormMain : Form { KsatClass[] Ksat;
Jeg har forsøgt at refresh'et formen forskellige steder med der kommer kun fejl ud af det. Det eneste der virker er min knap. Jeg bliver nødt til at forlade computeren en 2- 3 timer og har første mulighed for at teste i morgen når jeg kommer på arbejde til vægtene. MEN JEG VIL GIVE MIN HØJRE ARM (næsten) FOR AT SVAR 
Jeg har forresten testet zedviewklassen. Den virker fint, når data IKKE kommer fra serielporten med blot generes i en form. Så kører de to events fint og datagridwiew og zedgraph opdateres.
Hvad er det for en exception, du får på DataGridView.Refresh()?
Det kan skyldes noget multithread-halløj.
Det er kun den tråd (din hoved-tråd), der har oprettet DataGridView'ene, der må røre ved dem. Og jeg vil tro at Sartorius.DataReceived(...) kaldes på en baggrundstråd. Du kan undersøge det ved at sætte et breakpoint i DataReceived(...) og dernæst åbne Threads vinduet i Visual Studio (menu Debug|Windows|Threads).
I så fald skal du et sted skifte fra din baggrundstråd til din hoved-tråd, og det kunne du fx. gøre i starten af KsatClass.DataToGrid(...):
if (dgv.InvokeRequired) dgv.Invoke(new DataToGridDelegate(DataToGrid), new [] { data });
Du skal så også tilføje denne delegate erklæring til KsatClass klassen:
1000 tak!!! Det skal prøves, så snart jeg kommer på arbejde. Havde nok på fornemmelsen, at det var noget med det. Lige meget, hvordan jeg prøvede fik jeg fejl på refresh.
Hvis der er andre ting ved min kode som er uhensigtsmæssigt eller uprofessionelt så sig bare til - jeg vil gerne lære. Vender tilbage efter test...
Du havdere ret kza. Sartorius.DataReceived(...) var en workertråd. Når følger din anvisning opdateres grid og graf - nogen gange dog med en del forsinkelse. Der må være en hel masse igang, hvad mon der optager systemet??
Jeg er tror godt, jeg vil have et ekstra argument med i DataToGrid. Jeg vil gerne have tiden med, så den tid jeg knytter til vægten ikke afhænger af, hvornår der er tid til at opdatere. Hvordan gør jeg det? Har prøvet med: private delegate void DataToGridDelegate(string data, dateTime time); og if (dgv.InvokeRequired) dgv.Invoke(new DataToGridDelegate(DataToGrid), new [] { data, time }); men det virker ikke.
Sender du et svar kza? OG TIL DIG BLVI JEG OPRETTER LIGE ET EKSTRA SPØRGSMÅL, SÅ DU OGSÅ HAR MULIGHED FOR AT FÅ POINT FOR DIN HJÆLP.
Uprofessionel kode? Hmmm... Jeg har set "professionel kode", af utrolig svingende kvalitet.
Jeg har kigget det igennem og set, om jeg synes, noget kan gøres bedre (der er altid noget).
Fejlhåndtering: Du skal pakke koden i ZedView.AddRow ind i en try-catch blok. Og så skal du gøre noget i dine catch blokke. Fx: catch(Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); EventLog.WriteEntry(Application.ProductName, ex.ToString(), EventLogEntryType.Error); } skriv til en fil, send en mail eller et eller andet. Hvis du i dit oprindelig spørgsmål havde skrevet, hvilken exception du fik på Refresh(), så havde du fået svar meget hurtigere. Hvis du havde google't den, havde du måske selv fundet ud af det.
I ZedView ville jeg lytte på DataTable.RowChanged i steden for DataGridView.RowsAdded og DataGrid.RowsRemoved. I handleren til RowChanged kan du på e.Action se, om rækken er tilføjet eller fjernet. Hvorfor blande DataGridView ind i at ZedGraphControl skal opdateres, når der tilføjes data til DataTable?
Hvis du tegner dine klasser som kasser på et stykke papir, og så tegner pile mellem dem, der kender til hinanden, så skal du have så få pile som muligt.
Du kunne lade FormMain oprette ZedView'et og give det til KsatClass - så behøver KsatClass ikke kende noget til DataGridView og ZedGraphControl (der forsvand to pile).
Der er pile i begge retninger mellem Satorius og KsatClass - det er ikke helt godt. I steden for at Satorius kalder en metode i KsatClass, kan du lade Satorius fyre en event, som KsatClass lytter på, så behøver Satorius ikke have en reference til KsatClass.
FormMain_Load Jeg ville lave en metode, der tog nogle parametre ("COMx", zgX, dataGridViewX, timerX) og som så oprettede en Sartorius, en ZedView og en KsatClass, som den returnerede. Den skulle så kaldes 4 gange i FormMain_Load.
Et par småting:
Lav FormMain.Ksat om til en List<KsatClass>.
Satorius.IsNumeric(): I steden for en try-catch, der er tidskrævende, skal du bruge: double value; return double.TryParse(data, out value);
Og RYD OP Fjern udkommenteret kode og kommentarer, der ikke længere passer. Fjern metoder, properties og member-variable, der ikke skal bruges mere (fx. FormMain f).
Tak Kza! Jeg er mere en taknemmelig for dine råd. Jeg synes min kode køre noget sløvt. Opdatering af datagridview sker langsomt. Måske vil det lette at følge dine råd. Og det vil jeg sandsynligvis følge dem alle.
Skal have tykket dem stille og roligt igennem her i weekenden Så kommer der måske et par opklarende spørgsmål. Jeg har brugt mine 200 på dette spørgsmål men vil gerne belønne din indsats. Er det mon lovlig at oprette et nyt spørgsmål som du så kan besvare?
Jeg har ikke været særlig meget herinde, så jeg ved ikke helt hvordan det foregår.
Husk i øvrigt selv at tage stilling til mine råd. Kasser dem, du synes er dårlige eller spild af tid, og følg de andre.
Ingen af mine råd vil i øvrigt hjælpe dig med performance, med mindre du er begyndt at kalde IsNumeric() med try-catch blokken rigtig mange gange.
Et råd mht. performance optimering: Lav målinger! Lad være med at gætte på, hvor tiden går - mål, hvor den forsvinder. Hvis du gætter, gætter du forkert - det siger alle erfaringer.
Det kan du gøre med en Profiler fra fx. JetBrains eller redgate. Jeg har selv gode erfaringer med den fra YourKit. De har alle en gratis trial periode.
Men det tager lidt tid at sætte sig ind i dem. Så en hurtigere løsning er at tilføje
forskellige steder i koden, og så kigge i Output vinduet i VS mens programmet kører. Da dit program er multitrået, kan outputtet godt være temmelig forvirrende, så til at starte med bør du nok kun køre mod en COM port.
Men i morgen vil jeg nu gennemgå dine råd grundigt. Værd sød og se efter, om jeg har nogen spørgsmål - der kommer sikkert et par, Jeg opretter et ekstra spørgsmål "strømlining af kode" med 200 point.
Hej Kza Jeg kan ikke få følgende råd til at virke fuldstændigt: 'I ZedView ville jeg lytte på DataTable.RowChanged i steden for DataGridView.RowsAdded og DataGrid.RowsRemoved. I handleren til RowChanged kan du på e.Action se, om rækken er tilføjet eller fjernet. Hvorfor blande DataGridView ind i at ZedGraphControl skal opdateres, når der tilføjes data til DataTable?'
Eventen DataTable.RowChanged, kører når jeg tilføjer rækker til datatablet med IKKE når jeg sletter rækker fra datagridviewet. Men det er vel egentlig også klart ??
Det må betydet at sletning i datagiridviewet, ikke forplanter sig til datatablet.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.