2012-05-11 21 views
5

Mam formularz, który zawiera obrazek. Kiedy formularz wczytuje domyślny obraz ładuje się dobrze. Następnie aktualizuję obraz, gdy zmieni się coś w mojej formie, które zmienia wyświetlany obraz. Generowanie tego obrazu działa również dobrze, widzę obraz na dysku i otwieram go za pomocą farby itp. Ogólnie rzecz biorąc, robię to, otwierając strumień plików w lokalizacji obrazu, a następnie ustawiając obraz w tej lokalizacji.WinForm obrazka pokazuje pusty C#

if (this.picPreview.Image != null) 
{ 
    this.picPreview.Image.Dispose(); 
    this.picPreview.Image = null; 
} 
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); 
this.picPreview.Image = System.Drawing.Image.FromStream(fs); 

Ale bez względu na to, co robię, obraz pojawia się pusty na formularzu. Próbowałem odświeżenie formularza, odświeżenie kontrolki graficznej, ustawienie widocznej właściwości na widoczną, nic nie pomaga.

Tworzę oddzielny formularz, który zawiera tylko obrazek i przekazuje lokalizację obrazu do formularza i powtórzyć proces otwierania strumienia, a następnie ustawienie obrazu w tym miejscu działa idealnie.

Nie ma żadnych wyjątków podczas rzucania AFAIK ... debugger jest ustawiony na łamanie wszystkich wyjątków.

Co może powodować takie zachowanie?

Każda rada jest doceniana. Mam kolejną aplikację, która generuje obrazy w wątku pracującym w tle i to też działa dobrze.

Zapewnienie większej ilości informacji o tym, co próbuję zrobić, pomoże mi dojść do sedna. Dla każdego wiersza w moim datagridview znajduje się między jedną a trzema kolumnami, do których przypisany jest obraz. Z góry wygenerowałem wszystkie te obrazy. Przewijanie siatki Otrzymuję obraz podglądu pierwszej kolumny obrazu w moim polu graficznym za pomocą zdarzenia SelectionChanged. Działa idealnie. Mam również komórki, które po kliknięciu pokazują okno formularza z podglądem obrazów, które składają się na obraz w głównym formularzu. To również działa doskonale. Mogę zmienić wiersze i kliknąć komórki w siatce i wszystko działa. Zasadniczo buduję nowy obraz w oparciu o to, co wybiera użytkownik na innych kontrolkach, które są związane z datagridem.

Problem pojawia się, gdy próbuję zmienić obraz w ramce graficznej na formularzu głównym. Mogę zaktualizować źródło danych i zobaczyć aktualizację wartości siatki, ale obraz, który teraz zregeneruję za pomocą oprogramowania innej firmy, który mogę zweryfikować na dysku i jest widoczny po aktualizacji, po prostu znika. Kiedy to nastąpi, nie otrzymuję już obrazu w ramce graficznej w formularzu, dopóki nie zamknę formularza i nie otworzę go ponownie, a następnie wszystkie zaktualizowane dane są dostępne i wszystko działa ponownie. Kod, który zostanie wywołany przy wyborze, zmieniony tak, aby ustawić obraz jest dokładnie taki sam jak kod w miejscu, aby zaktualizować nowy obraz. Jest całkowicie synchroniczny. Brakuje mi pomysłów innych niż zaczynanie od zera z zupełnie nową formą.

Jeszcze raz dziękuję za wszystkie sugestie.

Zacznę od góry. Ogólny przepływ jest następujący:

Otwórz formularz zawierający datagrid powiązany z widokiem SQL. Dgv jest tylko do odczytu i tylko jeden wiersz może być wybrany na raz. Widok wypełnia się automatycznie wraz z kontrolkami, które są powiązane z każdą kolumną siatki. Należą do nich pola tekstowe dla niektórych, comboboxes i checkboxy dla pozostałych. Każdy wiersz zawiera skojarzony z nim zestaw obrazów. Po załadowaniu formularza mogę przewinąć widok, a dla każdego wiersza w polu graficznym w formularzu pojawi się nowy obraz. Wszystkie te obrazy zostały wstępnie wygenerowane. Po wybraniu wiersza w wierszu może znajdować się maksymalnie trzy obrazy, w którym to przypadku przyciski nawigacyjne są włączone, aby umożliwić użytkownikowi podgląd każdego obrazu.

Wybieram wiersz, zmieniam formanty w formularzu, aby zmienić jedną lub więcej wartości komórki w wybranym wierszu.Następnie kliknąłem przycisk zapisu, który aktualizuje bazę danych i odpowiednie dane w siatce. Następnie próbuję zaktualizować obrazy dla tego wiersza. W tym momencie ramka graficzna znika i tracę podglądy w formularzu razem; żadne obrazy nie pojawiają się, dopóki nie zamknę i ponownie nie otworzę formularza, a wszystko będzie dobrze, dopóki nie zrobię zapisu.

Próbując rozwiązać ten problem, stwierdzam, że aktualizacja powiązanego dgv powoduje wielokrotne wywołanie zdarzenia selectchanged. Istnieje kod obsługujący przypadki, w których powiązanie nie jest kompletne lub w widoku nie ma niczego wybranego. Istnieje również kod w procedurze obsługi btnSave_Click, który zawiesza procedurę obsługi zdarzeń "changechanged", aż do zakończenia aktualizacji i ponownego wygenerowania obrazu (ów). Pomimo tego, mimo że wybrany wiersz jest aktualizowany w widoku, faktycznie wybrany wiersz (gdzie znajduje się strzałka i co wszystkie kontrolki wyświetlają), pierwszy wiersz jest zawsze "bieżącym" wierszem po aktualizacji. Nie wiem jak to naprawić. Oto kod dla zmiany selekcji i przyciski obsługi zdarzeń zapisywania przycisków.

Oto zrzut ekranu w postaci: enter image description here

I kod dla SelectionChanged i btn_save obsługi zdarzeń:

/// <summary> 
     /// update the preview on a row selection change 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private void dataGridView1_SelectionChanged(object sender, EventArgs e) 
     { 
      if (!BindingComplete) return; 

      DataGridView dgv = (DataGridView)sender; 

      if (!dgv.Focused || dgv.CurrentRow == null) return;   

      // set the pic preview to the current row image(s) 
      // we need the record for the current index 
      DataRowView currentDataRowView = (DataRowView)dgv.CurrentRow.DataBoundItem; 

      if (currentDataRowView == null) return; 

      DataRow currentRow = currentDataRowView.Row; 

      LastSelectedIndex = dgv.SelectedRows[0].Index; 

      Debug.WriteLine("Current row in SelectionChanged: " + currentRow.ItemArray[0].ToString()); 

      bool showBox = false, showProd = false, showWire = false; 
      string box, prod, wire; 

      string pdcProductName = currentRow.ItemArray[0].ToString(); 

      showWire = !string.IsNullOrEmpty(wire = currentRow.ItemArray[7].ToString()); 

      showBox = !string.IsNullOrEmpty(box = currentRow.ItemArray[8].ToString()); 

      showProd = !string.IsNullOrEmpty(prod = currentRow.ItemArray[9].ToString()); 

      // check for wirepath, box, and product. Enable the nav buttons if there is more than 
      // one label for this product. We need to check for LabelFileName being the same for both 
      // box and product, in which case there is one file for both which defaults to box 
      if ((showBox && showProd && prod == box) || showBox) 
      { 
       string targetFile = PreviewImagePath + pdcProductName + "_eBox.png"; 

       if (picPreview.Image != null) 
       { 
        //picPreview.Image.Dispose(); 
        //picPreview.Image = null; 
       } 

       // if the preview image doesn't exist yet use a default image 
       if (!File.Exists(targetFile)) 
       { 
        // make the loading gif invisible 
        this.picLoading.Visible = true; 

        //picPreview.Image = AdminTILE.Properties.Resources.StandardPaper; 
       } 
       else 
       { 
        this.picLoading.Visible = false; 
        Debug.WriteLine("Opening file " + targetFile); 

        FileStream fs = new FileStream(targetFile, FileMode.Open, FileAccess.Read); 
        picPreview.Image = System.Drawing.Image.FromStream(fs); 
        Image imgCopy = (Image)picPreview.Image.Clone(); 
        this.picPreview.Visible = true; 
        fs.Close(); 

        // preview in another frame 
        if (frm.IsDisposed) 
        { 
         frm = new PreviewImage(); 
        } 
        frm.PreviewLabel(imgCopy); 
        frm.Show();     

        //picPreview.ImageLocation = targetFile; 
       } 
      }    
      else if (showProd) 
      { 
       string targetFile = PreviewImagePath + pdcProductName + "_eBox.png"; 

       if (picPreview.Image != null) 
       { 
        picPreview.Image.Dispose(); 
        //picPreview.Image = null; 
       } 

       if (!File.Exists(targetFile)) 
       { 
        // make the loading gif invisible 
        this.picLoading.Visible = true; 
        //picPreview.Image = AdminTILE.Properties.Resources.StandardPaper; 
       } 
       else 
       { 
        this.picLoading.Visible = false; 
        FileStream fs = new FileStream(targetFile, FileMode.Open, FileAccess.Read); 
        picPreview.Image = System.Drawing.Image.FromStream(fs); 
        fs.Close(); 
       } 
      }   

     } 


     /// <summary> 
     /// update the database with the current selections 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private void btnSave_Click(object sender, EventArgs e) 
     { 

      if (dataGridView1.SelectedRows.Count == 0) 
      { 
       MessageBox.Show("No record is selected to update"); 
       return; 
      } 

      DialogResult result1 = MessageBox.Show("Saving Label Configuration. Are you sure?", 
       "IMPORTANT!", MessageBoxButtons.YesNoCancel); 

      // update the view 
      if (result1 == DialogResult.Yes) 
      { 

       // we need the record for the current index 
       DataRowView currentDataRowView = (DataRowView)dataGridView1.CurrentRow.DataBoundItem; 
       DataRow currentRow = currentDataRowView.Row;     
       string pdcProductName = currentRow.ItemArray[0].ToString(); 



       Int32 currentIndex = dataGridView1.SelectedRows[0].Index; 

       Debug.WriteLine("Current index in Save:" + currentIndex.ToString()); 

       string AgencyId="", LogoId="", WireId=""; 

       SqlDataAdapter LabeledProductsDataTableAdapter = 
       new SqlDataAdapter("SELECT * FROM LabeledProducts", 
        printConfigTableAdapter.Connection); 

       SqlDataAdapter LogosDataTableAdapter = 
       new SqlDataAdapter("SELECT * FROM Logos", 
        printConfigTableAdapter.Connection); 

       if (vwTILEAdminTableAdapter.Connection.State != ConnectionState.Open) 
       { 
        printConfigTableAdapter.Connection.Open(); 
       } 

       DataTable LogoDataTable = new DataTable(); 
       LogosDataTableAdapter.Fill(LogoDataTable); 

       DataTable LabeledProductsDataTable = new DataTable(); 
       LabeledProductsDataTableAdapter.Fill(LabeledProductsDataTable); 

       StringBuilder sql = new StringBuilder(); 

       // Fill a table with the results of the 
       // data adapter and query the table instead of the database. 
       // An empty LogoDescription maps to an empty filename 
       DataRow dataRow; 

       if (cbAgency.SelectedItem != null) 
       { 
        sql.Append("LogoDescription = '").Append(cbAgency.SelectedItem).Append("'");      
        dataRow = LogoDataTable.Select(sql.ToString())[0]; 
        AgencyId = dataRow.ItemArray[0].ToString(); 

        sql.Clear(); 
       } 

       if (cbPrivateLabel.SelectedItem != null) 
       { 
        sql.Append("LogoDescription = '").Append(cbPrivateLabel.SelectedItem).Append("'"); 
        dataRow = LogoDataTable.Select(sql.ToString())[0]; 
        LogoId = dataRow.ItemArray[0].ToString(); 

        sql.Clear(); 
       } 

       if (cbWire.SelectedItem != null) 
       { 

        sql.Append("LogoDescription = '").Append(cbWire.SelectedItem).Append("'"); 
        dataRow = LogoDataTable.Select(sql.ToString())[0]; 
        WireId = dataRow.ItemArray[0].ToString(); 

        sql.Clear(); 
       } 


       // PdcProductName is the primary key 
       sql.Append(@"UPDATE [dbo].[LabeledProducts] 
        SET [PdcProductName] = @pdcProd 
         ,[LabelProductName] = @lblProd 
         ,[LabelDescription] = @lblDesc 
         ,[Power] = @pwr 
         ,[Fabrication] = 0 
         ,[UL_File_Number] = @ul 
         ,[PrePrintedSerial] = @pps 
         ,[ShowOrderOnLabel] = 0 
         ,[PrivateLabelLogoId] = @plid 
         ,[AgencyImageId] = @aid 
         ,[WireDiagConfigId] = @wid 
         ,[ReleasedForProduction] = @rfp 
        WHERE PdcProductName = '").Append(pdcProductName).Append("'"); 

       using (SqlCommand command = new SqlCommand(sql.ToString(), vwTILEAdminTableAdapter.Connection)) 
       { 
        if (vwTILEAdminTableAdapter.Connection.State != ConnectionState.Open) 
         vwTILEAdminTableAdapter.Connection.Open(); 

        LabeledProductsDataTableAdapter.UpdateCommand = command; 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@pdcProd", txtPdcProdName.Text); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@lblProd", txtLabeledProd.Text); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@lblDesc", txtLabelDesc.Text); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@pwr", txtPower.Text);      
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@ul", txtULFileNumber.Text); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@pps", cbPrePrintedSerial.Checked); 

        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@plid", LogoId); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@aid", AgencyId); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@wid", WireId); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@rfp", cbReleased.Checked); 

        //int rowsAffected = LabeledProductsDataTableAdapter.Update(LabeledProductsDataTable); 
        int rowsAffected = command.ExecuteNonQuery(); 

        // The DataViewManager returned by the DefaultViewManager 
        // property allows you to create custom settings for each 
        // DataTable in the DataSet. 
        DataViewManager dsView = this.tILEDataSet.DefaultViewManager; 

        // remove the selectionChanged event handler during updates 
        // every update causes this handler to fire three times!!! 
        this.dataGridView1.SelectionChanged -= new System.EventHandler(this.dataGridView1_SelectionChanged); 


        dataGridView1.DataSource = typeof(TILEDataSet.vwTILEAdminDataTable); 
        this.vwTILEAdminBindingSource.DataSource = typeof(TILEDataSet.vwTILEAdminDataTable); 
        this.vwTILEAdminBindingSource.DataSource = this.tILEDataSet.vwTILEAdmin; 
        this.dataGridView1.DataSource = this.vwTILEAdminBindingSource;      
        vwTILEAdminBindingSource.ResetBindings(false); // false for data change, true for schema change 

        this.vwTILEAdminTableAdapter.Fill(this.tILEDataSet.vwTILEAdmin); 

        // we need to reget the row after the update to pass to preview 
        currentIndex = LastSelectedIndex; 
        DataGridViewRow drv = this.dataGridView1.Rows[currentIndex]; 
        currentRow = ((DataRowView)(drv.DataBoundItem)).Row; 

        // update the preview files 

        UpdatePreviewFiles(currentRow); 


        // try this 
        dataGridView1.ClearSelection(); 
        // this doesn't work 
        dataGridView1.Rows[currentIndex].Selected = true; 


        // reset the selection changed handler once the update is complete 
        this.dataGridView1.SelectionChanged += new System.EventHandler(this.dataGridView1_SelectionChanged); 

       } 

      } 
     } 

Po aktualizacji postać wygląda tak samo z wyjątkiem skrzynka obraz zniknął , a dane z pierwszego wiersza są wyświetlane w kontrolkach, a nie w podświetlonym wierszu.

AfterSave

Wszystkie UpdatePreviewFiles robi to zastąpić obrazy ze zaktualizowanymi nich. Wszystko, co robi ShowPreview, to ustawienie obrazu w obrazku. Obraz. Wszystko działa, dopóki nie zrobię zapisu/aktualizacji.

Jeśli jest coś jeszcze, co mogę dostarczyć, daj mi znać, to zajmie zbyt dużo czasu, aby rozwiązać, wiem, że istnieje stosunkowo proste wyjaśnienie.

Jeszcze raz dziękuję.

+0

Mówisz, że działa poprawnie w uproszczonej wersji. Musisz więc zacząć przyglądać się różnicom między nimi. –

+0

Każdy cel używania filestream? – coder

+1

Czy zamykasz strumień? –

Odpowiedz

4

spróbować zrobić:

this.picPreview.Image = Image.FromFile(imagePath); 

Zamiast bawić z FileStream.

Po wyrzuceniu nie musisz ustawiać this.picPreview.Image na null. Po wywołaniu utylizacji, zwalnia wszystkie zasoby, niezależnie od tego, czy masz na to wskaźnik, czy nie.

Ustawienie wartości zerowej na coś lub w innych, dokładniejszych słowach, utratę odniesienia (wskaźnika) do obiektu - spowoduje, że GC (Garbage Collector) zwolni jego zasoby.

Użycie metody Rozmieść pozwoli GC ją zwolnić, nawet jeśli nadal masz do niej odniesienie. (Dzięki Rowland Shaw), więc po prostu ponowne ustawienie go na Image.FromFile(imagePath) będzie działało dobrze.

Odwołanie do poprzedniego obrazu zostanie utracone, a GC usunie je, kiedy będzie miało na to ochotę (nie będzie to długo, obiecuję).

Podsumowując, sugerowałbym zastąpienie CAŁKOWITĄ częścią kodu pojedynczą linią na początku tej odpowiedzi.

+0

Nie spowoduje to natychmiastowego wywozu śmieci - po prostu pozwala na to, gdy zostanie on wywołany (który będzie w momencie przydzielania pamięci, zakładając, że nie jest ręcznie wywoływany) –

+0

@RowlandShaw Dzięki za informację! Naprawiono :) – SimpleVar

+0

Używanie Image.FromFile nie robi różnicy. Obraz pojawia się, gdy formularz się ładuje, wszystko co robię, to aktualizowanie go w miejscu. Również w tej samej formie renderuje się dobrze w ramach tej samej metody. Nie znalazłem żadnej różnicy między obrazkami. Ale dziękuję. – Gary