5

ピクチャボックスを含むフォームがあります。フォームが読み込まれると、デフォルトの画像が正常に読み込まれます。次に、フォーム内の何かが変更され、表示されている画像が変更されたときに画像を更新します。この画像の生成も正常に機能します。ディスク上の画像を表示し、ペイントなどで開くことができます。一般に、画像の場所でファイル ストリームを開き、画像をこの場所に設定します。

 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);

しかし、私が何をしても、画像はフォーム上で空白に見えます。フォームを更新し、picturebox コントロールを更新し、visible プロパティを visible に設定しようとしましたが、何も役に立ちません。

ピクチャボックスのみを含む別のフォームを作成し、画像の場所をフォームに渡し、ストリームを開いて画像をこの場所に設定するプロセスを繰り返します。これは完全に機能します。

私の知る限り例外はスローされていません...デバッガーはすべての例外で中断するように設定されています。

この動作の原因は何ですか?

アドバイスをいただければ幸いです。バックグラウンドワーカースレッドで画像生成を行う別のアプリケーションがあり、それも正常に動作します。

私がやろうとしていることについて、より多くの背景を提供することで、この問題の根底にたどり着くことができるかもしれません。私のdatagridviewのすべての行には、画像が関連付けられている1〜3列があります。これらの画像はすべて事前に生成しました。グリッドをスクロールすると、SelectionChanged イベントを使用して、画像ボックスの最初の画像列のプレビュー画像を取得します。それは完全に機能します。また、クリックすると、メインフォームの画像を構成する画像のプレビューを含むフォームウィンドウを表示するセルもあります。これも完璧に機能します。行を変更してグリッド内のセルをクリックすると、すべてが機能します。基本的に、データグリッドにバインドされている他のコントロールでユーザーが選択したものに基づいて、新しい画像を作成しています。

メイン フォームの画像ボックスの画像を変更しようとすると、問題が発生します。データソースを更新し、グリッド値が更新されるのを確認できますが、サードパーティのソフトウェアを使用して再生成した画像は、ディスク上にあり、更新後に表示できることを確認できますが、消えてしまいます。これが発生すると、フォームを閉じて再度開くまで、フォームの画像ボックスに画像が表示されなくなり、更新されたすべてのデータがそこにあり、すべてが再び機能します。画像を設定するために選択が変更されたときに呼び出されるコードは、新しい画像を更新するために配置されたコードとまったく同じです。完全同期です。まったく新しい形でゼロから始める以外のアイデアが不足しています。

すべての提案に感謝します。

上から始めます。全体の流れは次のとおりです。

SQL ビューにバインドされたデータグリッドを含むフォームを開きます。dgv は読み取り専用で、一度に 1 行しか選択できません。ビューは、グリッドの各列にバインドされたコントロールと共に自動的に入力されます。これらには、一部のテキスト ボックス、その他のコンボ ボックスおよびチェックボックスが含まれます。各行には、関連付けられた一連の画像があります。フォームが読み込まれると、ビューを下にスクロールでき、行ごとに新しい画像がフォームの画像ボックスに表示されます。これらの画像はすべて事前に生成されています。行を選択すると、その行に最大 3 つの画像が表示される場合があります。この場合、ナビゲーション ボタンが有効になり、ユーザーは各画像をプレビューできます。

行を選択し、フォームのコントロールを変更して、選択した行の 1 つ以上のセル値を変更します。次に、保存ボタンをクリックすると、データベースとグリッド内の対応するデータが更新されます。次に、この行の画像を更新しようとします。この時点で画像ボックスが消え、フォームのプレビューがすべて失われます。フォームを閉じて再度開くまで画像は表示されず、保存するまではすべて正常です。

これを解決しようとすると、バインドされた dgv を更新すると、selectchanged イベントが複数回発生することがわかりました。バインドが完了していない場合、またはビューで何も選択されていない場合を処理するコードがあります。btnSave_Click ハンドラーには、更新が完了してイメージが再生成されるまで、selectionchanged イベント ハンドラーを一時停止するコードもあります。これを行っても、更新した行がビューで選択されていても、実際に選択された行 (矢印が配置されている場所、およびすべてのコントロールが表示するもの) は、最初の行が常に更新後の「現在の」行です。それを修正する方法はまだわかりません。変更された選択とボタン保存イベント ハンドラーのコードを次に示します。

フォームのスクリーン ショットを次に示します。ここに画像の説明を入力

また、selectionchanged および btn_save イベント ハンドラのコードは次のとおりです。

/// <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);

                }

            }
        }

更新後、画像ボックスがなくなったことを除いて、フォームは同じように見え、ハイライトされた行ではなく、最初の行のデータがコントロールに表示されます。

保存後

UpdatePreviewFiles が行うのは、画像を更新されたものに置き換えることだけです。ShowPreview が行うのは、画像を picturebox.Image に設定することだけです。保存/更新を行うまで、すべて機能します。

他に提供できることがあれば教えてください。これは解決に時間がかかりすぎます。比較的簡単な説明があることはわかっています。

再度、感謝します。

4

1 に答える 1

4

やってみてください:

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

いじる代わりにFileStream

また、廃棄後に設定this.picPreview.Imageする必要はありません。nulldispose を呼び出すと、ポインタがあるかどうかに関係なく、すべてのリソースが解放されます。

null を何かに設定する、またはより正確に言えば、オブジェクトへの参照 (ポインター) を失うと、GC (ガベージコレクター) がそのリソースを解放します。

Dispose メソッドを使用すると、参照が残っていても、GC はそれを解放できます。(Rowland Shaw に感謝します)、単純に再設定するImage.FromFile(imagePath)だけで問題なく動作します。

前のイメージへの参照は失われ、GC は必要に応じてそれを破棄します (そう長くはかかりませんが、約束します)。

要約すると、この回答の冒頭にあるコード全体を1行に置き換えることをお勧めします。

于 2012-05-11T17:32:31.293 に答える