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

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

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

フォームの全ての値を保存・読み込む方法

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

■88370 / inTopicNo.1)  フォームの全ての値を保存・読み込む方法
  
□投稿者/ アビド (1回)-(2018/08/23(Thu) 22:20:50)

分類:[.NET 全般] 


https://social.msdn.microsoft.com/Forums/ja-JP/0abebc73-d730-49e7-834b-166409cfe8e1/12501124571254012512123982051612434204452534512375123902742522?forum=vbgeneralja

このページと同じ質問です。

VB.NETを使っていて、
フォームにある全てのテキストボックス、コンボボックス、NumericUpDownなどの値を
保存して、
次にそのプログラムを開いた時に読み込んで復元したいのですが
どのようにすれば良いですか?

このページを読んでみると
http://dobon.net/vb/dotnet/programing/mysettings.html

設定のタブで一つ一つパラメータを保存するように設定する必要があると思います。

数が多いと手作業でやるのは非常に面倒です。

自動で、全てのパラメータを保存・読み込みするようなことってできないでしょうか?




引用返信 編集キー/
■88371 / inTopicNo.2)  Re[1]: フォームの全ての値を保存・読み込む方法
□投稿者/ Azulean (984回)-(2018/08/24(Fri) 06:24:55)
No88370 (アビド さん) に返信
> 設定のタブで一つ一つパラメータを保存するように設定する必要があると思います。
> 数が多いと手作業でやるのは非常に面倒です。
> 自動で、全てのパラメータを保存・読み込みするようなことってできないでしょうか?

設定(Settings)は明示的に値を定義し、そこに保存する仕様なので、自動でやるといったことはできません。
また、標準の仕組みは用意されていないので、「自動でまとめて保存」をするためには自分でそういった仕組みを作る必要があります。

フォーム内のすべての Controls を foreach で列挙し、場合によっては再帰的に列挙し、コントロールの種類に応じて保存するべき値を XML に書き込むといったようなものです。
たとえば、TextBox なら ReadOnly でなければ Text を保存するなど、自分が望む条件で実装していく必要があります。

そういった仕組みを自力で作るのと、設定を使うのがどちらが楽かは人によります。
また、アプリケーションの画面が複雑化していくと、自動で保存する仕組みでカバーするのが逆に大変になるかもしれません。
引用返信 編集キー/
■88372 / inTopicNo.3)  Re[2]: フォームの全ての値を保存・読み込む方法
□投稿者/ アビド (2回)-(2018/08/24(Fri) 09:14:45)


ありがとうございます。

http://www.atmarkit.co.jp/fdotnet/dotnettips/224controls/controls.html

このページを参考にして、
コントロールの値を取得する方法は分かりました。





    Public Function GetAllControls(ByVal top As Control) As Control()
        Dim buf As ArrayList = New ArrayList
        For Each c As Control In top.Controls
            buf.Add(c)
            buf.AddRange(GetAllControls(c))
        Next
        Return CType(buf.ToArray(GetType(Control)), Control())
    End Function


        Dim all As Control() = GetAllControls(Me)
        For Each c As Control In all
            Dim c_Name = c.Name

            If c.GetType Is GetType(NumericUpDown) Then

                Dim c_Value = CType(c, NumericUpDown).Value

            End If

        Next

あとは、得られた値を反映させる方法なのですが、
文字列からコントロールを指定するにはどのようにしたら良いですか?

http://blog.hiros-dot.net/?p=4590

                Me.Controls(c_Name).vallue = 5

のようにして、指定したいのですが
うまくいきません。

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=29420&forum=7

10年以上前の記事ですが、

Dim s() As String = {"0", "1", "2", "3", "4"} 
Dim i As Integer = 0 
Do while i < 5 
Dim ctrl As Control = FindControl(Me, "テキスト" + cstr(i + 1)) 
ctrl.Text = s(i) 
i = i + 1 
Loop 

 FindControlを使うしかないのでしょうか?




引用返信 編集キー/
■88373 / inTopicNo.4)  Re[1]: フォームの全ての値を保存・読み込む方法
□投稿者/ 774RR (627回)-(2018/08/24(Fri) 09:58:37)
フォーム上に配置できる部品は System.Windows.Forms.Control 派生クラスだと考えてよくて、そうすると
System.Windows.Forms.Control.Label とか
System.Windows.Forms.Control.GroupBox とか
System.Windows.Forms.Control.ProgressBar とか
どう考えても保存・復帰にふさわしくない部品がいっぱいある。

だから「全部の値」の保存と簡単に考えるべきでないんだろうとオイラは思うの心。 Microsoft がそういう手段を提供していないのは無理もない。

真にやりたいのはフォーム上の部品の状態保存ではない、に1票。
では真にやりたいことが何であるかは質問者でないとわからないので、ちょっと手を止めて検討しなおしてみることを推奨したい。


引用返信 編集キー/
■88374 / inTopicNo.5)  Re[2]: フォームの全ての値を保存・読み込む方法
□投稿者/ アビド (3回)-(2018/08/24(Fri) 10:12:07)
保存したいのは
Textboxやコンボボックスなど
ユーザーが変更可能なものだけです
引用返信 編集キー/
■88375 / inTopicNo.6)  Re[3]: フォームの全ての値を保存・読み込む方法
□投稿者/ アビド (5回)-(2018/08/24(Fri) 10:26:33)

HashTableにコントロールをアイテムとして、
コントロール名をキーとして入れれば
できそうな気がします。



    Public Function GetAllControls2(ByVal top As Control) As Hashtable
        Dim buf As Hashtable = New Hashtable
        For Each c As Control In top.Controls


            Dim c_nama = c.Name

            Add(buf, GetAllControls2(c))
        Next
        Return buf
    End Function


    Public Shared Function Add(ByVal first As Hashtable, ByVal second As Hashtable) As Hashtable
        Dim table As Hashtable = New Hashtable
        For Each e As DictionaryEntry In first
            table.Add(e.Key, e.Value)
        Next
        For Each e As DictionaryEntry In second
            If Not table.ContainsKey(e) Then
                table.Add(e.Key, e.Value)
            End If

        Next
        Return table
    End Function



のようにしてやってみたのですが、
なぜかTableLayoutpanelの下層に入っている
コントロールのNameが空になってしまいます。

ArrayListを使った方法で
 CType(buf.ToArray(GetType(Control)), Control())
のようにコントロール配列にキャストしてやると
Nameが入るようになるようです。

キャストせずにNameが入るようにするにはどうしたら良いですか?





引用返信 編集キー/
■88377 / inTopicNo.7)  Re[4]: フォームの全ての値を保存・読み込む方法
□投稿者/ せば (4回)-(2018/08/24(Fri) 11:37:56)
色々意味が分からない。
> のようにしてやってみたのですが、
> なぜかTableLayoutpanelの下層に入っている
> コントロールのNameが空になってしまいます。

どの時点でどのように確認した結果をおっしゃってますか?
「Hashtable」であれば、頑張ろうとしてるのは分かりますが
そもそも、「Name」を追加する箇所自体存在しません。

> ArrayListを使った方法で
> CType(buf.ToArray(GetType(Control)), Control())
> のようにコントロール配列にキャストしてやると
> Nameが入るようになるようです。
>
> キャストせずにNameが入るようにするにはどうしたら良いですか?

キャストしてNameが入るのであれば、キャストせずともNameは入ると思うんですが。。
キャストせずにNameとは、具体的にはどのコード??

とりあえずキャストせずに返却してみる

Public Function GetAllControls(ByVal top As Control) As ArrayList
Dim buf As ArrayList = New ArrayList
For Each c As Control In top.Controls
buf.Add(c)
buf.AddRange(GetAllControls(c))
Next
Return buf
End Function

とりえあずNameを表示してみる
Dim all As ArrayList = GetAllControls(Me)
For Each c As Control In all
MessageBox.Show(c.Name)
Next



引用返信 編集キー/
■88379 / inTopicNo.8)  Re[5]: フォームの全ての値を保存・読み込む方法
□投稿者/ アビド (7回)-(2018/08/24(Fri) 11:43:10)
Add(buf, GetAllControls2(c))
となっているのが原因でした
buf=Add(buf, GetAllControls2(c))

とすると解決しました。

ちなみにハッシュテーブルで
キーからアイテムを取得するのは
内部的には、
配列をForループで検索するのと同じ操作を行っているのでしょうか?

速度的には、ハッシュテーブルを使うのと
自分で配列からForループで検索するのでは
どちらの方が高速でしょうか?

引用返信 編集キー/
■88380 / inTopicNo.9)  Re[4]: フォームの全ての値を保存・読み込む方法
□投稿者/ 魔界の仮面弁士 (1794回)-(2018/08/24(Fri) 12:10:10)
No88375 (アビド さん) に返信
> For Each c As Control In top.Controls
>  Dim c_nama = c.Name
>  Add(buf, GetAllControls2(c))
> Next

これ、Name プロパティを拾うだけで、実際には使用していませんよね。

また、「Function Add(first, second) As Hashtable」の戻り値を利用していませんし、
Hashtable.Add の呼び出しも不足しているのでは…。



> HashTableにコントロールをアイテムとして、
> コントロール名をキーとして入れれば
> できそうな気がします。

ちなみに Name プロパティは一意とは限りません。一応念のため。

Visual Studio 上のデザイナ上では制限されていますが、.NET 実装としては
同名コントロールや無名コントロールも許容されていたりします。
(だからこそ .Controls.Find は、結果を配列で返却するわけで)

たとえば DataGridView や NumericUpDown は、Name が空の子コントロールを有しています。


No88374 (アビド さん) に返信
> 保存したいのは
> Textboxやコンボボックスなど
> ユーザーが変更可能なものだけです

データを復元する際の処理順序に制限がかかるケースもありえます。
たとえばデータバインディングが行われている場合のバインド順序など。

TextBox にしても、長い文章の 3 行目全体が選択状態になっていて、
その選択状態まで復元しようとするなら、先に Text プロパティを復元してから
選択範囲を復元する必要がありますよね。(選択後に文章を書き換えると選択解除されてしまうので)

また、TextChanged や SelectedIndexChanged や CheckedChanged のように
プロパティ変更通知イベントが使われていた場合、値を書き換えることで
イベントが発生するため、どのコントロールの情報から復元していくかで
結果に影響を与える可能性がありえます。

これらへの個別対処が求められることもありえます。


NumericUpDown などでは、プロパティ設定が Minumum ≦ Value ≦ Maximum の関係に
なっていないと例外を発生させる仕様になっていますので、これらを書き換える場合には
ISupportInitialize を利用するか、あるいはプロパティの設定順序や値の範囲に
気を配るなどの対処が求められることになりますし。
引用返信 編集キー/
■88381 / inTopicNo.10)  Re[6]: フォームの全ての値を保存・読み込む方法
□投稿者/ 魔界の仮面弁士 (1795回)-(2018/08/24(Fri) 12:46:30)
2018/08/24(Fri) 13:52:51 編集(投稿者)

No88379 (アビド さん) に返信
> 配列をForループで検索するのと同じ操作を行っているのでしょうか?

そもそも配列にしても、
 Private items() As String = {"Google", "Apple", "Microsoft", "Amazon" }
というデータがある場合、「2 番目のアイテム」を取得するために、
全件ループなんてしないですよね。
"Microsoft" の位置を取得する場合はループ処理になりますが。


Hashtable の場合も、同様で「Key で指定した Value」を取得するために、
全件ループは行いません。


かなり大雑把に言うと、Hashtable に Add される際には、
指定された Key に対して Object.GetHashCode メソッドを通じて
Int32 なハッシュが算出され、これを管理番号として扱っています。

このとき、別々の Key が、偶然同じハッシュ値を返すこともありえるので、
その場合は「衝突」として、次の管理番号位置にハッシュ情報が格納されます。

取り出すときは、Key からハッシュを得て、そこから管理番号の位置を算出し、
その管理番号がもつ Value を取り出します。

※細かい点を端折っているので、正確な表現では無いですが。


> 速度的には、ハッシュテーブルを使うのと
> 自分で配列からForループで検索するのでは
> どちらの方が高速でしょうか?

For や Array.IndexOf の場合はループ操作になるので、
個数 n に比例して最大捜索時間がのびます。いわゆる O(n) 操作。

それに対して、Hashtable のインデクサアクセスでは、
個数によらず処理時間はほぼ一定で済みます。いわゆる O(1) 操作。
全てのキーが同じハッシュ値を返すようだと O(n) になりますけれどね。


ハッシュテーブルの概念については、下記を参照してみてください。
https://wa3.i-3-i.info/word11947.html
https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB

.NET の Hashtable の内部実装については、下記を参照してみてください。
https://referencesource.microsoft.com/#mscorlib/system/collections/hashtable.cs
引用返信 編集キー/
■88388 / inTopicNo.11)  Re[5]: フォームの全ての値を保存・読み込む方法
□投稿者/ アビド (8回)-(2018/08/24(Fri) 18:58:09)
丁寧なご回答ありがとうございます。

何とか、これで作れると思います
解決済み
引用返信 編集キー/

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


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

このトピックに書きこむ