Visual Basic 中学校 掲示板
投稿内容
タグのない投稿を抽出
統計
RSS
Visual Basic 中学校
>
投稿一覧
>
モーダル表示中に他のフォームを操作したい
タグの編集...
投稿者
アシタカ
 (学生)   投稿日時
2021/12/16 15:34:21
いつもお世話になっております。
ちょっと色々試行錯誤していて気になったので教えて下さい。
【前提】
Form1がメイン画面
Form2がモーダルフォーム
Form3がモードレスフォーム
という構成でフォーム画面を作っています。
【実現したい事】
メイン画面からForm3(モードレスフォーム)を表示
その後Form2(モーダルフォーム)を表示
この時にForm3(モードレスフォーム)を操作できるようにしたいです。
よろしくお願いいたします。
投稿者
魔界の仮面弁士
 (社会人)   投稿日時
2021/12/16 15:59:45
モーダル側から、モードレス画面のLabel の値を変更したりするぐらいはできますが、
モーダル表示中に非モーダルな画面を、ユーザーが操作可能な形にすることはできません。
ユーザー操作を許可したいのであれば、モーダル画面を使わずに
モードレスで表示するようにしてください。
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=30668
投稿者
アシタカ
 (学生)   投稿日時
2021/12/16 17:24:37
下記のような内容を見つけたのですが、
https://teratail.com/questions/34440
これはvb.netだと難しいんでしょうか?
投稿者
(削除されました)
 ()   投稿日時
2021/12/16 17:50:53
(削除されました)
投稿者
魔界の仮面弁士
 (社会人)   投稿日時
2021/12/16 19:08:05
モーダル表示中に、それ以前に表示されていた既存フォームを操作することはできません。
(モーダル表示中に、新たなモードレスフォームを表示することならばできます)
今回のケースであれば、Form2 をモーダルで呼ばずに、
モードレスとして呼び出すだけで解決できる話だと思うのですが、
それが出来ない理由は何ですか?
投稿者
(削除されました)
 ()   投稿日時
2021/12/16 19:55:48
(削除されました)
投稿者
魔界の仮面弁士
 (社会人)   投稿日時
2021/12/16 20:08:28
> 今回のケースであれば、Form2 をモーダルで呼ばずに、
> モードレスとして呼び出すだけで解決できる話だと思うのですが、
> それが出来ない理由は何ですか?
当初の質問から推察して、現状は
①Form1 から Form3 が呼び出されている(モードレス)
②Form2 は Form3 の表示後に表示される画面である
③Form2 がどこから呼び出されるのかは明記されていないが
Form2 は現状、モーダル ダイアログとして呼び出している ★それは何故?
④Form2 がモーダルなので、Form2 表示中は Form1 や Form3 を触れない状態である
⑤Form2 がモーダルなので、Form2 が閉じられるまで呼び出し元は待機状態となる
⑥Form2 が表示された後、先に表示されていた Form3 が触れないのを何とかしたい
という状況なのですよね。
この場合、⑥ の事象は ③ が原因で引き起こされているわけですから、
それならばモードレスにしてはどうでしょうか、というのが私の提案となります。
(以前に表示されていたフォームを触れてしまったら、それは modal とは言えないと思いますし…)
しかしモードレスにすると、④と⑤の振る舞いが変わってきますので、ここで追加確認させてください。
➍ Form2 の表示中に、Form3 だけでなく Form1 も操作可能になると、何か問題がありますか?
➎ Form2 が閉じられるまで、呼び出し元が ShowDialog の結果を待ち合わせる実装で無いと困りますか?
4/5のどちらも必須事項では無いのなら、
Form2 を ShowDialog から Show に変えるだけで済むと思います。
4が問題だというのなら、Form3 を表示する前に Form1 を Enabled = False にしておき、
Form3 が閉じられたときに、Form1 を Enabled = True に戻す処理を書くという手が使えます。
Form1 のコントロールが淡色表示になってしまうのが難点ですけれども。
5が問題なのであれば、Form3 はモードレスで表示しつつ、
フォームが閉じられるのを Async/Await を使って待ち合わせるという手があります。
Partial
Public
Class
Form2
Inherits
Form
''' <summary>
''' モードレスだけどモーダル表示っぽく振る舞わせてみる
''' </summary>
Public
Async
Function
ShowDialogAsync()
As
Task(
Of
DialogResult)
Dim
tcs
As
New
TaskCompletionSource(
Of
DialogResult)()
Dim
closedHandler
As
FormClosedEventHandler =
Nothing
closedHandler =
Sub
(sender
As
Object
, e
As
FormClosedEventArgs)
RemoveHandler
FormClosed, closedHandler
'フォームが閉じられた時、完了状態に遷移させる
'SetResult : 正常終了
'SetCanceled : キャンセル
'SetException : 例外発生
tcs.SetResult(
Me
.DialogResult)
End
Sub
AddHandler
FormClosed, closedHandler
Dim
hideHandler
As
EventHandler =
Nothing
hideHandler =
Sub
(sender
As
Object
, e
As
EventArgs)
If
Me
.Visible
Then
Return
RemoveHandler
VisibleChanged, hideHandler
'フォームが非表示になった時、完了状態に遷移させる
tcs.SetResult(DialogResult.Cancel)
End
Sub
AddHandler
VisibleChanged, hideHandler
'モーダルではなく、モードレスで表示
Me
.Show(Owner)
'Await を使って、完了まで待ち合わせてみる
Return
Await tcs.Task
End
Function
'普通のモーダル ダイアログであれば、
'デザイン時に Button1.DialogResult 等を設定しておくだけで
'Yes/No/Cancel な閉じるボタンの動作となります。
'
'しかしモードレスの場合にはその機能が稼働しないため、
'自分で DialogResult や Close を呼ぶなどして
'同等の機能を作りこむ必要があります。
#Region
"Yes/No/Cancel ボタン"
Private
Sub
Button1_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button1.Click
Me
.DialogResult = DialogResult.Yes
Me
.Close()
End
Sub
Private
Sub
Button2_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button2.Click
Me
.DialogResult = DialogResult.No
Me
.Close()
End
Sub
Private
Sub
Button3_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button3.Click
Me
.DialogResult = DialogResult.Cancel
Me
.Close()
End
Sub
#End
Region
End
Class
'Form2 の呼び出し元
Private
Sub
Button1_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button1.Click
'普通のモーダルダイアログ呼び出し
Dim
f
As
DialogResult
Using
f3
As
New
Form3()
f = f3.ShowDialog(
Me
)
End
Using
MsgBox(f.ToString())
End
Sub
Private
Async
Sub
Button2_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button2.Click
'モードレスだけど疑似的にモーダルっぽく動作させる
Me
.Enabled =
False
Dim
f
As
DialogResult
Using
f3
As
New
Form3()
f = Await f3.ShowDialogAsync()
End
Using
Me
.Enabled =
True
MsgBox(f.ToString())
End
Sub
投稿者
魔界の仮面弁士
 (社会人)   投稿日時
2021/12/16 20:44:49
何度か書き直していましたが、まだ間違いが残ってた…。 orz
> Using f3 As New Form3()
済みません。モーダル表示していたいのは、Form3 ではなく Form2 でしたっけね。
上記の「New Form3()」の部分は、「New Form2()」に読み替えてください。
> Public Async Function ShowDialogAsync() As Task(Of DialogResult)
Hide() あるいは Visible = False で閉じられた場合、
本来の ShowDialog であれば DialogResult.Cancel が返されますが、
今回の ShowDialogAsync だと DialogResult.None が返されています。御了承ください。
投稿者
KOZ
 (社会人)   投稿日時
2021/12/17 03:03:54
> 下記のような内容を見つけたのですが、
> https://teratail.com/questions/34440
> これはvb.netだと難しいんでしょうか?
VB.NET で記述できますが、アプリケーションフレームワークは使わないほうがいいかもしれません。
作りをざっと見た感じだと、マルチスレッドで動くことを前提に作られていない気がします。
(1) 「アプリケーションフレームワークを有効にする」のチェックを外し、スタートアップオブジェクトを Sub Main にします。
(2) Program.vb というモジュールを作成し以下のコードを書きます。
Public
Module
Program
<STAThread>
Sub
Main()
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(
False
)
Application.Run(
New
Form1())
End
Sub
End
Module
(3) Form1 にボタンを貼り付けて、以下のコードを書きます。
Public
Class
Form1
Private
Class
OwnerHandle
Implements
IWin32Window
Public
Sub
New
(
ByVal
handle
As
IntPtr)
Me
.Handle = handle
End
Sub
Public
ReadOnly
Property
Handle
As
IntPtr
Implements
IWin32Window.Handle
End
Class
Private
Sub
Form1_Load(sender
As
Object
, e
As
EventArgs)
Handles
MyBase
.Load
Dim
owner
As
New
OwnerHandle(
Me
.Handle)
Task.Run(
Sub
()
Dim
form3
As
New
Form3()
form3.Show(owner)
Application.Run(form3)
End
Sub
)
End
Sub
Private
Sub
Button1_Click(sender
As
Object
, e
As
EventArgs)
Handles
Button1.Click
Dim
form2
As
New
Form2()
form2.TopMost =
True
form2.ShowDialog()
End
Sub
End
Class