C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

フォーム間のデータ渡しをスムーズに

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■95975 / inTopicNo.1)  フォーム間のデータ渡しをスムーズに
  
□投稿者/ コーヒー好き (1回)-(2020/10/14(Wed) 09:17:22)

分類:[C#] 

Visual C#プログラムの質問です。

Form1(メインフォーム)、Form2(子フォーム)、2つのフォーム間で情報を共有したいのですが、
Form1で計算したデータが膨大な数になるので、Form2に渡すときに動作が重くなってしまっています。
(Form2 Load イベントのところで、Form1のデータを読み込むようにプログラムしています。)

Form2 Load イベントのところで一気にデータを読み込まないように、
Form1に計算を繰り返している最中に細目にデータをForm2に渡すようにしようと思い、
Form2のインスタンスをあらかじめ作成しておき、計算しながらForm2にデータを渡すようにしたのですが
今度はForm2を閉じてしまうとインスタンスが破棄されてしまうのでデータを渡せなくなってしまう。

何かいい方法あればご教授お願い致します。
引用返信 編集キー/
■95976 / inTopicNo.2)  Re[1]: フォーム間のデータ渡しをスムーズに
□投稿者/ 魔界の仮面弁士 (2872回)-(2020/10/14(Wed) 09:46:25)
No95975 (コーヒー好き さん) に返信
> Form1に計算を繰り返している最中に細目にデータをForm2に渡すようにしようと思い、
> Form2のインスタンスをあらかじめ作成しておき、計算しながらForm2にデータを渡すようにしたのですが
> 今度はForm2を閉じてしまうとインスタンスが破棄されてしまうのでデータを渡せなくなってしまう。

計算結果のインスタンス管理を Form2 に任せているのは何故ですか?

どういうデータなのか分かりませんし、どのように引き渡しているのかも分かりませんが、
計算を Form1 で行っているのなら、その計算結果は Form1 上(あるいはアプリケーション単位)で
保持しておき、Form2 にはそのデータクラスへの参照を渡すだけにすれば良いのでは無いでしょうか。
引用返信 編集キー/
■95977 / inTopicNo.3)  Re[2]: フォーム間のデータ渡しをスムーズに
□投稿者/ 774RR (836回)-(2020/10/14(Wed) 09:59:56)
普通に参照型 (=class) で計算結果を持てば引き渡しは参照だけだし...
引用返信 編集キー/
■95978 / inTopicNo.4)  Re[1]: フォーム間のデータ渡しをスムーズに
□投稿者/ 大谷刑部 (113回)-(2020/10/14(Wed) 10:08:18)
No95975 (コーヒー好き さん) に返信
> Visual C#プログラムの質問です。
> Form2 Load イベントのところで一気にデータを読み込まないように、
> Form1に計算を繰り返している最中に細目にデータをForm2に渡すようにしようと思い、
> Form2のインスタンスをあらかじめ作成しておき、計算しながらForm2にデータを渡すようにしたのですが
> 今度はForm2を閉じてしまうとインスタンスが破棄されてしまうのでデータを渡せなくなってしまう。
見た目閉じた状態にしたいだけならばhideにすればいいだけでは?
それにCloseとDisposeは別概念なので、Form閉じる=インスタンスの破棄ではありませんよ。少なくともFormオブジェクト自体は。
モーダレスの場合にCloseメソッドでDisposeを同時に行っているということに過ぎません。

詳しくは以下を参照してください。
https://dobon.net/vb/dotnet/form/closeform.html


> 何かいい方法あればご教授お願い致します。
聞きたいのは
(1)受渡しの手段自体ですか?
(2)それとも受渡し方法はすでに確定済みなので、単純に複数フォームでの想定データの受渡のメモリ負荷を軽くする方法を知りたいのですか?

いずれにしても「データ」が何(グリッド等なのか、変数値なのか、テキストボックス等の値なのか)かによっておそらく最適解は変わると思うので、
もう少し内容を開示してください。
引用返信 編集キー/
■95980 / inTopicNo.5)  Re[3]: フォーム間のデータ渡しをスムーズに
□投稿者/ ぶなっぷ (253回)-(2020/10/14(Wed) 10:40:34)
以下のような記述があるということは、
> (Form2 Load イベントのところで、Form1のデータを読み込むようにプログラムして
>   います。)

データはForm1が持っているんですよね?
Form2が閉じて、渡せなくなった際に何が困るのでしょう?

 1) データがどんどん溜まって、いつかバッファがあふれてしまう
 2) Form2が再度開かれた際に、データを再送するが、再送処理が重い
 3)   :

問題は、Form2が閉じられたことを、どう解釈するか?だと思います。

処理のキャンセルだとみなすなら、データはクリアでしょう。
一時的にForm2が閉じられただけとみなすなら、Form2が再度開いたら再送ですが、
「その前にバッファがあふれてしまった場合」の検討、および、
「再送時にも重くならないようにする方法」の検討が必要かと思います。

質問内容が漠然としているので、まずは仕様レベルでのお話をさせていただきました。

引用返信 編集キー/
■95981 / inTopicNo.6)  Re[1]: フォーム間のデータ渡しをスムーズに
□投稿者/ kiku (198回)-(2020/10/14(Wed) 10:40:40)
No95975 (コーヒー好き さん) に返信
> Form2 Load イベントのところで一気にデータを読み込まないように、
> Form1に計算を繰り返している最中に細目にデータをForm2に渡すようにしようと思い、
> Form2のインスタンスをあらかじめ作成しておき、計算しながらForm2にデータを渡すようにしたのですが
> 今度はForm2を閉じてしまうとインスタンスが破棄されてしまうのでデータを渡せなくなってしまう。

すでに掲示板の回答にある参照を受け渡すというのを
具体的なソースサンプルは下記になります。
あくまでも一例ですが。
理解の助けになれば良いですが。

    public partial class Form1 : Form
    {
        public List<string> Result = new List<string>();
        private Form2 form2;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //重たい計算
            foreach(var i in Enumerable.Range(1, 10))
            {
                Result.Add(i.ToString());
            }

            //Form2をモードレスダイアログとして起動
            form2 = new Form2();
            form2.Owner = this;
            form2.Show();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(form2 != null)
            {
                form2.Dispose();
                form2 = null;
            }
        }
    }

    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            //Form1から計算結果の参照を取得
            var result = ((Form1)Owner).Result;

            //計算結果を表示
            foreach (var s in result)
            {
                Console.WriteLine(s);
            }
        }
    }

引用返信 編集キー/
■95983 / inTopicNo.7)  Re[4]: フォーム間のデータ渡しをスムーズに
□投稿者/ コーヒー好き (3回)-(2020/10/14(Wed) 12:57:57)
>皆様

ご丁寧に回答頂き有難う御座います。

Form1ではスレッドタイマーを用いてcountを加算させていき、
count毎に1000個のデータをdouble型2次元配列 data[100000,1000] に格納させていく処理を行っています。

Form2ではForm1の data[100000,1000] のデータをグラフ化する処理を行っており、
Form1から設定を変更してグラフの横軸、縦軸の操作をしたいのでモーダレスでForm2は開きたい思いがあります。

やりたいこととしましては、複数フォームでの想定データの受渡のメモリ負荷を軽くする方法です。

Form1でcount毎に計算した1000個のデータはcount加算の度にForm2の方に受け渡していき、
一気に受け渡すこと無く処理させたいです。
Form2の×ボタンで押してCloseメソッドでDisposeしてしまっていますが、
×ボタンでDisposeせずに、hideにすることはできるのでしょうか?

それができれば解決しそうです。。。

引用返信 編集キー/
■95984 / inTopicNo.8)  Re[5]: フォーム間のデータ渡しをスムーズに
□投稿者/ 大谷刑部 (114回)-(2020/10/14(Wed) 14:13:11)
No95983 (コーヒー好き さん) に返信
> >皆様
>
> ご丁寧に回答頂き有難う御座います。
>
> Form1ではスレッドタイマーを用いてcountを加算させていき、
> count毎に1000個のデータをdouble型2次元配列 data[100000,1000] に格納させていく処理を行っています。
>
> Form2ではForm1の data[100000,1000] のデータをグラフ化する処理を行っており、
> Form1から設定を変更してグラフの横軸、縦軸の操作をしたいのでモーダレスでForm2は開きたい思いがあります。
>
> やりたいこととしましては、複数フォームでの想定データの受渡のメモリ負荷を軽くする方法です。
メモリ負荷を気にするのであれば、2次元配列をやめた方がいいと思います。特にサイズが大きすぎる気がします。
負荷云々以前に要素数が多すぎて処理が激烈に重くなるのは必然です。

.netではいろいろ選択肢も多いので他の手段も検討された方がいいのでは?
行・列に相当するものが表現できればいいので、
DataTable、List、コレクションーーーー。
手段としてはいろいろあり得ると思います。


> Form1でcount毎に計算した1000個のデータはcount加算の度にForm2の方に受け渡していき、
> 一気に受け渡すこと無く処理させたいです。
> Form2の×ボタンで押してCloseメソッドでDisposeしてしまっていますが、
> ×ボタンでDisposeせずに、hideにすることはできるのでしょうか?
form2がモーダルであればCloseとDisposeは挙動的に分離できますが、モーダレスの場合はそのままだとDisposeが発動しますね。
FormClosingイベントでイベントで、計算中はイベントキャンセルしたうえでhideとかですかね。
FormClosedだとおそらく間に合わないでしょうし、Diposedだと破棄したあとなので当然ダメです。
やったことないので、はっきりしたことは言えませんが、Dispose単独のキャンセルは難しいようでしょうね。

引用返信 編集キー/
■95985 / inTopicNo.9)  Re[5]: フォーム間のデータ渡しをスムーズに
□投稿者/ 魔界の仮面弁士 (2874回)-(2020/10/14(Wed) 15:29:04)
2020/10/14(Wed) 15:37:33 編集(投稿者)

No95983 (コーヒー好き さん) に返信
> Form2の×ボタンで押してCloseメソッドでDisposeしてしまっていますが、
> ×ボタンでDisposeせずに、hideにすることはできるのでしょうか?

FormClosing イベントで、e.CloseReason を確認し、
ユーザー操作(UserClosing)で閉じられた場合は、
e.Cancel = true; this.Hide(); としては如何でしょう。

ついでに、Form2 のオーナーフォームに Form1 を指定しておけば、
Form1 が閉じられたときに、Form2 も Dispose されるようになります。


> モーダレスで
.NET Framework 界隈の場合は、
モーダレス(modal-less) ではなく
モードレス(modeless) 表記の方が一般的です。


> Form1ではスレッドタイマーを用いてcountを加算させていき、
> count毎に1000個のデータをdouble型2次元配列 data[100000,1000] に格納させていく処理を行っています。

配列という事は……単純計算で 762.9 MiB 相当ですね。
これらすべてをオンメモリで保持しなければならないのですか?
count が小さいうちは、後半部が使われないメモリ構造なのが気になりますが、
可変サイズにしていないということは、起動時にメモリを確保しておきたいという意図でしょうか。


1000 個単位でカウントアップされるようなので、恐らくは
data[count, 0〜999] という形で管理されているのだと見受けました。

そうすると、たとえば count が 0 から 1 へと増えた場合、
data[1, 0〜999] の領域のみが Form2 に渡したい情報ということでしょうか。
あるいは data[0, 0〜999] の部分も、読み取り専用として扱われるのでしょうか。

ImmutableArray や ReadOnlySpan<> が使える環境でも無いでしょうし、
この配列を Form2 がどのように扱いたいのかが気になりました。


それと、スレッドタイマーが使われている点も厄介に思えます。

今回のデータは、count と data という 2 つの変数で管理されているようですが、
count および data の読み書きは、メインスレッドでしか行われない仕様でしょうか?

もしもその変数を、スレッドタイマーと UI スレッドの双方で利用しているのであれば、
「両変数の値を書き換えている最中」に、その内容が他から読み書きされない事を
何らかの形で保証する必要があろうかと思います。


> Form2ではForm1の data[100000,1000] のデータをグラフ化する処理を行っており、

データが 100,000,000 (1 億個)もあったら、グラフでは表現しきれないのではないでしょうか。
3840 x 2160 の 4K モニターでも、総ピクセル数はわずか 8,294,400 程度ですよね。

データ全体ではなく、データの一部のみ(たとえば 1000 個のみ)を受け渡すにしても、
2 次元配列で管理する仕様のままでは、扱いにくいと思いますよ。

・データの一部をコピーしてから渡す手法は、2 次元配列との相性が悪い。
・データ全体を参照で渡す方法だと、スレッドセーフを保証するための維持コストが問題になるかもしれない。
・データの一部のみを参照で受け渡す手法(ArraySegment<T> 等)も使えない。
引用返信 編集キー/
■95987 / inTopicNo.10)  Re[6]: フォーム間のデータ渡しをスムーズに
□投稿者/ コーヒー好き (4回)-(2020/10/14(Wed) 18:09:59)
>皆様

再度、返答有難う御座います。

2次元配列やめて、Datatable等で数値の受け渡しの方、試みてみようと思います。

2次元配列よりDatatableの方が処理速度が速いのが一般的なのでしょうか?
引用返信 編集キー/
■95989 / inTopicNo.11)  Re[7]: フォーム間のデータ渡しをスムーズに
□投稿者/ 魔界の仮面弁士 (2875回)-(2020/10/14(Wed) 18:33:05)
2020/10/14(Wed) 19:19:27 編集(投稿者)

No95987 (コーヒー好き さん) に返信
> 2次元配列よりDatatableの方が処理速度が速いのが一般的なのでしょうか?

いえ。DataTable は相当「重い」クラスです。

変更通知や、修正前データの保持や入力値検査などといった、
高度な機能を多数備えていることもあり、
今回のような大量のデータ保持にはお奨めしません。
また、インスタンスを繰り返し使いまわすような用途にも向きません。
http://www.moonmile.net/blog/archives/7217
http://bbs.wankuma.com/index.cgi?mode=al2&namber=81781&KLOG=140
https://j.mp/3jYWGD0
https://www.cresco.co.jp/blog/entry/6016/


現状、2 次元配列をどのように扱っていたのかが分かりませんし、
同時アクセス制御を考慮する必要があるかどうかも不明なので、
代替案を提案しにくいところですが、たとえば

・ジャグ配列 double[][]
・1 次元配列 double[] + System.ArraySegment<double>
・System.Collections.Generic.List<double[]>
・System.Collections.Concurrent.ConcurrentDictionary<int, YourData>

などを使ってみるのは如何でしょう。


ただしどの方法を使うにしても、1億個もの倍精度浮動小数点数を
扱おうとすれば、メモリの確保/解放だけでも結構な負荷になりえます。

もしも実際に必要なデータが直近の千個〜一万個程度で十分であり、
それ以外の数千万個のデータにアクセスすることがほぼ無い場合には、
メモリ上のデータを必要最小限にするために、計算結果を
ランダムアクセスファイル等に退避しておくことも検討してみてください。
引用返信 編集キー/
■95992 / inTopicNo.12)  Re[8]: フォーム間のデータ渡しをスムーズに
□投稿者/ コーヒー好き (5回)-(2020/10/14(Wed) 20:25:06)
>魔界の仮面弁士さん

ご丁寧に有難う御座います。感謝です。

2次元配列ではなく、ジャグ配列 double[][] にすると多少軽くなる、とは聞いたことがあります。

トライしてみようと思います。

ちなみにdouble型をint型にすると扱うデータ量も変わってくるので動作も軽くなりますでしょうか?

なるべくデータ数を減らす方法で検討を進めてみようと思います。

有難う御座います。
引用返信 編集キー/
■96001 / inTopicNo.13)  Re[9]: フォーム間のデータ渡しをスムーズに
□投稿者/ 大谷刑部 (115回)-(2020/10/15(Thu) 10:26:16)
No95992 (コーヒー好き さん) に返信
> >魔界の仮面弁士さん
> ちなみにdouble型をint型にすると扱うデータ量も変わってくるので動作も軽くなりますでしょうか?
確かに扱う領域は減ると思いますが、グラフの精度は大丈夫なんですか?
速くなっても、アプリの仕様的に精度劣化したんじゃ本も子もないと思いますけど。

整数しか扱わないならintでいいと思いますが、小数扱うなら、まだdouble→floatへのダウンサイジングの方がましと思いますけど。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ