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

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

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

Re[12]: SizeChangedにコードを書くとエラーが出てしまう


(過去ログ 157 を表示中)

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

■91366 / inTopicNo.1)  SizeChangedにコードを書くとエラーが出てしまう
  
□投稿者/ 麺 (1回)-(2019/06/18(Tue) 18:09:29)

分類:[.NET 全般] 

PictureBox1内に四角や丸を描画しているのですが、
フォームのリサイズに連動して、PictureBox1がリサイズされた時に、
四角や丸の位置がずれないように再設定するコードを書きたいと考えています。


Public Sub PictureBox1_SizeChanged() Handles PictureBox1.SizeChanged
Public Sub Form1_SizeChanged() Handles MyBase.SizeChanged

上記のいずれかのそのコードを書けば良いことは分かるのですが、
ここに、そのコードを書くと、
アプリケーション起動時に、

application.designer.vb


Protected Overrides Sub OnCreateMainForm()
Me.MainForm = Global.WindowsApplication1.Form1
End Sub

のところで以下のエラーが出てしまいます。


型 'System.InvalidOperationException' のハンドルされていない例外が xxx.exe で発生しました

追加情報:フォームの作成中にエラーが発生しました。詳細については、Exception.InnerException を参照してください。 エラー:'WindowsApplication1.yyy' のタイプ初期化子が例外をスローしました。


エラーの原因を特定するために、
以下のように意味のないコードだけ書いて実行してみたのですが
それでもやはりエラーが出ます。

If aaaBool = True then

End If

aaaBoolは別のモジュールでPublic変数として定義しているbooleanです。


If aaaBool = True then
のところをコメントアウトするとエラーが出なくなるので、
ここに原因があるのは間違いありません。

実は、別のプログラムでも
SizeChangedを使ったコードを書いているのですが、
そちらは特にエラーなく実行できています。

そのコードとエラーの出るコードの違いはほとんどないのですが、
なぜかこのエラーが出てしまいます。

これは一体何が原因でしょうか?



引用返信 編集キー/
■91368 / inTopicNo.2)  Re[1]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ Azulean (1067回)-(2019/06/18(Tue) 22:39:05)
No91366 (麺 さん) に返信
> 型 'System.InvalidOperationException' のハンドルされていない例外が xxx.exe で発生しました
>
> 追加情報:フォームの作成中にエラーが発生しました。詳細については、Exception.InnerException を参照してください。 エラー:'WindowsApplication1.yyy' のタイプ初期化子が例外をスローしました。

そのエラーメッセージが示すように、InnerException に設定されている、実際に起きている例外情報を確認しないと先に進めないと思います。
「詳細の表示」とか、「例外の詳細をクリップボードにコピー」とか、そのメッセージとともに表示されているアクションで例外の詳細を確認してみてください。
引用返信 編集キー/
■91369 / inTopicNo.3)  Re[2]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ 麺 (2回)-(2019/06/18(Tue) 23:07:11)
ありがとうございます。

確かに詳細を取得することができました。

以下がエラーメッセージなのですが、
なにやら再帰処理していると書かれていますが、
何が原因か分かりますでしょうか?


System.TypeInitializationException はユーザー コードによってハンドルされませんでした。
HResult=-2146233036
Message='WindowsApplication1.Program_run' のタイプ初期化子が例外をスローしました。
Source=xxxプログラム
TypeName=WindowsApplication1.Program_run
StackTrace:
場所 WindowsApplication1.Form1.PictureBox1_SizeChanged() 場所 D:\xxxプログラム\sln\Form1.vb:行 1344
場所 WindowsApplication1.Form1._Lambda$__R123-2(Object a0, EventArgs a1)
場所 System.Windows.Forms.Control.OnSizeChanged(EventArgs e)
場所 System.Windows.Forms.Control.UpdateBounds(Int32 x, Int32 y, Int32 width, Int32 height, Int32 clientWidth, Int32 clientHeight)
場所 System.Windows.Forms.Control.UpdateBounds(Int32 x, Int32 y, Int32 width, Int32 height)
場所 System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
場所 System.Windows.Forms.Control.SetBounds(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
場所 System.Windows.Forms.Control.set_Location(Point value)
場所 WindowsApplication1.Form1.InitializeComponent() 場所 D:\xxxプログラム\sln\Form1.Designer.vb:行 931
場所 WindowsApplication1.Form1..ctor() 場所 D:\xxxプログラム\sln\Form1.vb:行 945
InnerException:
HResult=-2146233079
Message=既定のインスタンスからの作成中に、フォームがそれ自体を参照し、無限再帰の原因になりました。 フォームのコンストラクター内では、'Me' を使用してそのフォームを参照してください。
Source=xxxプログラム
StackTrace:
場所 WindowsApplication1.My.MyProject.MyForms.Create__Instance__[T](T Instance) 場所 :行 181
場所 WindowsApplication1.My.MyProject.MyForms.get_Form1()
場所 WindowsApplication1.Program_run..cctor() 場所 D:\xxxプログラム\sln\Program_run.vb:行 10
InnerException:


引用返信 編集キー/
■91370 / inTopicNo.4)  Re[3]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ Azulean (1068回)-(2019/06/18(Tue) 23:35:43)
2019/06/18(Tue) 23:39:04 編集(投稿者)

No91369 (麺 さん) に返信
> 以下がエラーメッセージなのですが、
> なにやら再帰処理していると書かれていますが、
> 何が原因か分かりますでしょうか?

PictureBox1_SizeChanged の中で Form1.〇〇 といったコードを書いていませんか?

1.アプリケーション起動時に Form1 を最初に作ろうとする
2.その中でデザイナで設定された初期サイズを PictureBox1.Size に反映しようとする
3.反映しようとした結果、PictureBox1_SizeChanged イベントが起きる
4.PictureBox1_SizeChanged の中に書かれた「Form1.〇〇」は暗黙/既定のインスタンス Form1 を参照したいが、まだ Form1 は完成していないので、Form1 を作ろうとする
5.2 番に戻り、以下繰り返し

言えることがあるとすれば…。

・Form1.〇〇 と書いた場合、Me(自分自身)ではなく、暗黙/既定のインスタンスを指し示すことを学んでおいてほしい
・自分自身を参照したいのなら、Form1.〇〇といった暗黙/既定のインスタンスではなく、Me キーワードを使って欲しい

参考
http://blogs.wankuma.com/jeanne/archive/2006/10/25/42449.aspx


(追記)
PictureBox1_SizeChanged に直接 Form1.〇〇 と書いていなくても、PictureBox1_SizeChanged に書かれている処理から間接的に Form1.〇〇 を見てしまうコードがあるなら、無限ループ(再帰)してしまいます。
結果としては、アルゴリズムを見直してくださいとなりそうです。
引用返信 編集キー/
■91372 / inTopicNo.5)  Re[4]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ 麺 (3回)-(2019/06/19(Wed) 04:25:12)
PictureBox1_SizeChanged にはForm1は書かれてありません。
上で述べた通り、別のモジュールで定義している
変数のみです。
その別のモジュールはForm1とは無関係ですので
再帰しているように見えないのですが・・・
引用返信 編集キー/
■91373 / inTopicNo.6)  Re[5]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ Azulean (1069回)-(2019/06/19(Wed) 06:17:50)
No91372 (麺 さん) に返信
> PictureBox1_SizeChanged にはForm1は書かれてありません。
> 上で述べた通り、別のモジュールで定義している
> 変数のみです。
> その別のモジュールはForm1とは無関係ですので
> 再帰しているように見えないのですが・・・

見えないとしても、事実は「Form1 を何らかの形で参照している」ことを示しています。
たとえば、参照している変数を定義しているモジュール内に、Form1 を見るコードが存在していれば実行されうると思います。

これ以上は、再現できるサンプルを示すなど、もっと手元の状態を見えるようにしていただかないとコメントは難しいです。

引用返信 編集キー/
■91375 / inTopicNo.7)  Re[3]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ PANG2 (303回)-(2019/06/19(Wed) 10:37:14)
No91369 (麺 さん) に返信
> 場所 WindowsApplication1.Form1.PictureBox1_SizeChanged() 場所 D:\xxxプログラム\sln\Form1.vb:行 1344
> 場所 WindowsApplication1.Form1..ctor() 場所 D:\xxxプログラム\sln\Form1.vb:行 945

Form1のコンスタクタでPictureBox1_SizeChangedが呼ばれていますね。

これを避けるには、

> Public Sub PictureBox1_SizeChanged() Handles PictureBox1.SizeChanged

Public Sub PictureBox1_SizeChanged()

Form1_Loadで

AddHandler Picture1.SizeChanged, AddressOf PictureBox1_SizeChanged

引用返信 編集キー/
■91379 / inTopicNo.8)  Re[4]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ 麺 (4回)-(2019/06/19(Wed) 15:00:43)
ありがとうございます。


Public xxx As Control = Form1

という変数定義が見つかったため、
= Form1
をコメントアウトしたところ、うまく実行できることが分かりました。
しかし、別のプログラムだと
この変数定義があっても、問題なく実行できているのが
不思議です。

> Form1のコンスタクタでPictureBox1_SizeChangedが呼ばれていますね。

もしかしてこれが原因なのでしょうか?

引用返信 編集キー/
■91380 / inTopicNo.9)  Re[5]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ PANG2 (304回)-(2019/06/19(Wed) 18:02:40)
2019/06/19(Wed) 18:03:04 編集(投稿者)

Public Class Form1
Private Sub PictureBox1_SizeChanged(sender As Object, e As EventArgs) Handles PictureBox1.SizeChanged
'If Not Me.Visible Then Return
System.Diagnostics.Debug.WriteLine(aaaBool)
End Sub
End Class

Module Module1
Public xxx As Control = Form1
Public aaaBool As Boolean
End Module

Form1のコンストラクタとModule1のコンストラクタで無限再帰しますね。

No.91370
の指摘どおり。

引用返信 編集キー/
■91404 / inTopicNo.10)  Re[6]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ 麺 (5回)-(2019/06/21(Fri) 14:35:24)
どうもありがとうございました。

解決済み
引用返信 編集キー/
■91431 / inTopicNo.11)  Re[7]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ 麺 (6回)-(2019/06/25(Tue) 21:06:02)
よくよく考えてみるとやはりエラーが出る理由が分からなくなりました。

Module Module1
Public xxx As Control = Form1
Public aaaBool As Boolean
End Module

のところがModuleではなく以下のようにClassなら

Module Class1
Public xxx As Control = Form1
Public aaaBool As Boolean
End Class


Form1で、aaaBoolが呼ばれるたびに、
Public xxx As Control = Form1
も生成されるわけなので、
無限ループするのは理解できます。

しかし、今のようにModuleとして宣言しているのであれば、
プログラムを起動時に、

Public xxx As Control = Form1

Public aaaBool As Boolean
が宣言され、
Form1からaaaBoolが呼ばれたとしても
xxxは再度生成されるわけではないので
無限ループしていないと思うのですが・・・

あるいは、 aaaBoolが宣言される前にxxxが宣言されてしまうと
aaaBoolがまだ存在していないので、
Form1でエラーになるという意味なのでしょうか?

Public xxx As Control = Form1
Public aaaBool As Boolean
と二つ並べて書いた場合、
どちらが先に宣言・実行されるかって
制御できませんよね?

こういう理解で合っていますでしょうか?


引用返信 編集キー/
■91432 / inTopicNo.12)  Re[8]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ Azulean (1073回)-(2019/06/25(Tue) 21:30:46)
2019/06/25(Tue) 22:59:41 編集(投稿者)

No91431 (麺 さん) に返信
> プログラムを起動時に、
> Public xxx As Control = Form1
> と
> Public aaaBool As Boolean
> が宣言され、

その認識が異なるのでしょう。
今の現象を引き起こすことから推察としては:

1.Module1 のメンバーに初めてアクセスした時点で Module1 が初期化されようとする
2.その結果、xxx には Form1 の暗黙のインスタンスで初期化する書かれているので、Form1 の暗黙のインスタンスが参照されるが、未作成なので Form1 を作成しようとする
3.Form1 のコンストラクタ起因で SizeChanged が発生し、aaaBool を参照するが、Module1 の初期化が完了していないので「初めてアクセスした」とみなされ、Module1 が初期化されようとする
4.その結果、Form1 の暗黙のインスタンスが参照されるが、まだ初期化が完了していない=未作成なので Form1 を作成しようとする
以下ループ(再帰)

※実際にはループが起こらず、Form1 の生成中に再度 Form1 を参照しようとしたことを検出して例外(エラー)になる。

> あるいは、 aaaBoolが宣言される前にxxxが宣言されてしまうと
> aaaBoolがまだ存在していないので、
> Form1でエラーになるという意味なのでしょうか?

宣言する順番は関係ありません。
メンバーに初期値を代入する構文を書いている(As Control = Form1)ので、Module1 を初めて参照したときに暗黙的に呼び出される、Module1 の初期化処理の中で Form1 を参照して xxx に代入する流れになっています。
(Module1 のメンバーのいずれかにアクセスできるようになるには、Module1 の中で初期値代入すると書いたものすべてに初期値の設定が完了している必要がある)
引用返信 編集キー/
■91433 / inTopicNo.13)  Re[9]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ 麺 (7回)-(2019/06/25(Tue) 22:58:12)
>> aaaBool を参照するが、Module1 の初期化が完了していないので「初めてアクセスした」とみなされ、

ここを勘違いしていました。

Module1の初期化が全て完了していなかったとしても
Form1が必要としている
aaaBoolさえ初期化が完了していれば、
再度、Form1が初期化されることはないと思っていました。

これってFormに限らず、
Public変数を含んだクラスのインスタンスを生成する場合には、
常に、Publicで行うのではなく、
全てのPublic変数の宣言が終わった後で
どこかのサブルーチン内で行わないといけないことを意味するのでしょうか?
今ままで、このようなエラーに遭遇したことがなかったのですが
たまたま運が良かっただけでしょうか?

引用返信 編集キー/
■91434 / inTopicNo.14)  Re[10]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ Azulean (1074回)-(2019/06/25(Tue) 23:04:37)
No91433 (麺 さん) に返信
> これってFormに限らず、
> Public変数を含んだクラスのインスタンスを生成する場合には、
> 常に、Publicで行うのではなく、
> 全てのPublic変数の宣言が終わった後で
> どこかのサブルーチン内で行わないといけないことを意味するのでしょうか?

前提にずれがありそうなのでこのあたりは、ノーコメントとしておきます。


> 今ままで、このようなエラーに遭遇したことがなかったのですが
> たまたま運が良かっただけでしょうか?

そういうことになるのでしょう。
こういった循環参照を防ぐには、Module や Shared、暗黙のインスタンスをなるべく使わないことです。
インスタンスを明示的に生成する・参照する・受け渡すことを意識していれば、「作ってないものは手に入らないのでどうしようもない」(このような事態になりようがない)ということになるためです。

もっとも、その徹底は難しいので、Module や Shared にはプリミティブ型(大雑把には Integer など、複雑な機能を持たないもの)だけに絞るとか、慎重に設計・実装するということになるでしょうね。
引用返信 編集キー/
■91435 / inTopicNo.15)  Re[11]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ PANG2 (306回)-(2019/06/26(Wed) 03:29:39)
2019/06/26(Wed) 03:36:56 編集(投稿者)

Form1のコンストラクタで PictureBox1_SizeChanged が走るのは意図せぬ動きなので、何らかの問題が発生する可能性はあります。

Private Sub PictureBox1_SizeChanged(sender As Object, e As EventArgs) Handles PictureBox1.SizeChanged
If Not Me.Visible Then Return

とかで、回避するべきです。

これは、VB特有の問題です。

C#なら、そこは考慮されていて、Form1.designer,cs で
PictureBoxのSizeを設定した後に、PictureBox1_SizeChanged イベントハンドラが登録されるので同様な問題は発生しません。
引用返信 編集キー/
■91440 / inTopicNo.16)  Re[12]: SizeChangedにコードを書くとエラーが出てしまう
□投稿者/ KOZ (4回)-(2019/06/27(Thu) 01:18:27)
No91435 (PANG2 さん) に返信
> Private Sub PictureBox1_SizeChanged(sender As Object, e As EventArgs) Handles PictureBox1.SizeChanged
> If Not Me.Visible Then Return
> 
> とかで、回避するべきです。

わたしのおすすめは Control を継承して CanRaiseEvents をオーバーライドすること。

Public Class PictureBoxEx
    Inherits PictureBox

    Private _CanRaiseEvents As Boolean = False

    Protected Overrides ReadOnly Property CanRaiseEvents As Boolean
        Get
            If Not _CanRaiseEvents AndAlso FindForm() IsNot Nothing Then
                _CanRaiseEvents = True
            End If
            Return _CanRaiseEvents
        End Get
    End Property

End Class

コントロールがフォームに追加されるまで、Events リストで管理されたイベントは発生しなくなります。
イベントに書く手間が省けます。

引用返信 編集キー/


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

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -