Calling Forms from Dialogs
In order to initiate a FormDialog you can just do:
var myform = new FormDialog<CreateNewLeadForm>(new CreateNewLeadForm(), CreateNewLeadForm.BuildForm, FormOptions.PromptInStart, null);
context.Call<CreateNewLeadForm>(myform, FormCompleteCallback);
Take a look to the PizzaBot for an example.
To initiate new dialogs within a Dialog you can do:
- context.Call passing the instance of the new dialog and the completion callback (as in the form)
context.Forward where you can forward the message to the child dialog
context.Forward(new MyChildDialog(), ResumeAfterChildDialog, message, CancellationToken.None);
Calling form from another form in Bot Framework
I reproduced your issue when set context.Wait
in the ResumeAfter
method of the first formflow dialog. This will make the second dialog ends when user sets the first filed of formflow dialog 2. Since you didn't post all code, I assume this is the problem.
Then to solve this problem, we need to wait for the result of whole formflow dialog instead of waiting for the first filed of formflow dialog, means we need to correctly use context.Wait
method, do not wait for use input if you want call the second formflow in the ResumeAfter
method of first formflow dialog.
I will call the first and second dialog both from a RootDialog
here as an example, if you want to use your first formflow dialog as a root dialog, it's a similar case.
My two FormFlow
dialog is like this:
[Serializable]
public class FFDialog1
{
public string Test { get; set; }
public string Description { get; set; }
public static IForm<FFDialog1> BuildForm()
{
return new FormBuilder<FFDialog1>()
.Message("Welcome to the first FormFlow dialog")
.Field(nameof(Test))
.Field(nameof(Description))
.Build();
}
}
public enum YesOrNo
{
Yes,
No
}
[Serializable]
public class FFDialog2
{
public YesOrNo? Confirmation;
public string Input { get; set; }
public static IForm<FFDialog2> BuildForm()
{
return new FormBuilder<FFDialog2>()
.Message("Welcome to the second FormFlow dialog")
.Field(nameof(Confirmation))
.Field(nameof(Input))
.Build();
}
}
And in RootDialog
, I call them like this:
[Serializable]
public class RootDialog : IDialog<object>
{
public Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
//call the first formflow dialog
var form = new FormDialog<FFDialog1>(new FFDialog1(), FFDialog1.BuildForm, FormOptions.PromptInStart, null);
context.Call(form, ResumeAfterFirstFFDialog);
}
private async Task ResumeAfterFirstFFDialog(IDialogContext context, IAwaitable<object> result)
{
var dialog = await result as FFDialog1;
//call the second formflow dialog according to the result of first one.
if (dialog.Test != null && dialog.Description != null)
{
var form = new FormDialog<FFDialog2>(new FFDialog2(), FFDialog2.BuildForm, FormOptions.PromptInStart, null);
context.Call(form, ResumeAfterSecondFFDialog);
}
}
private async Task ResumeAfterSecondFFDialog(IDialogContext context, IAwaitable<object> result)
{
//get result of formflow dialog 2.
var dialog = await result as FFDialog2;
await context.PostAsync("Work is done!");
context.Wait(MessageReceivedAsync);
}
}
Here I didn't set OnCompletion
of first formflow dialog cause the result will be submit when calling ResumeAfterFirstFFDialog
, it's the same to call second one in this method.
WinForms - Show dialog and still use the calling form
Call the Show
method instead of ShowDialog
.
This method is a non-blocking call (unlike ShowDialog
, it will return immediately, not after the new form closes) and will not show the form modally.
You'll probably want to pass the parent form as the parameter so that it will show as a child form.
Which is a better way to call Form.ShowDialog()?
Neither one is "better" than the other; they are perfectly equivalent!
However, in this particular case, both are wrong. The ShowDialog
method requires you to call the Dispose
method on the form. Unlike the Show
and Close
combination, this is not done automatically. From MSDN:
When a form is displayed as a modal dialog box, clicking the Close button (the button with an X at the upper-right corner of the form) causes the form to be hidden and the DialogResult property to be set to
DialogResult.Cancel
. Unlike non-modal forms, theClose
method is not called by the .NET Framework when the user clicks the close form button of a dialog box or sets the value of theDialogResult
property. Instead the form is hidden and can be shown again without creating a new instance of the dialog box. Because a form displayed as a dialog box is hidden instead of closed, you must call theDispose
method of the form when the form is no longer needed by your application.
Thus, you should choose between one of these (equivalent) forms:
using (Form1 frm = new Form1())
{
frm.ShowDialog();
}
or
Form1 frm = new Form1();
frm.ShowDialog();
frm.Dispose();
The reason that ShowDialog
doesn't automatically dispose the form is simple enough, if not immediately obvious. It turns out that applications often wish to read values from an instance of a modal dialog form after the form has been closed, such as settings specified in the form's controls. If the form were automatically disposed, you would be unable to read those values by accessing properties of the form object. Thus, the programmer is responsible for disposing forms shown as modal dialogs when (s)he is finished with them.
Passing value from dialog form to main form
Create public property in FormTask
public string Opgave { get {return textBoxOpgave.Text;}}
And check it after ShowDialog();
FormTask formTask = new FormTask(exerciseType);
formOpgaveInvoer.ShowDialog();
formOpgaveInvoer.Opgave; // here it is
MS Bot with Multiple Form Dialog
To call a dialog, you need to use context.Call
as explained in this post. However, I'm not fully sure if this will work in the OnCompletion
event of a Form.
If it doesn't work, my recommendation would be to encapsulate the RootForm
into a IDialog<object>
dialog and use that dialog as the starting point for the Conversation.SendAsync
of the controller.
Open a form from modal form that opened from parent form
Display your "child" form by setting TopLevel
to false:
Form f = new Form();
f.ShowInTaskbar = false;
f.BackColor = Color.Black;
f.Size = this.Size;
f.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
f.StartPosition = FormStartPosition.CenterParent;
f.Opacity = 0.6;
notificationSize nds = new notificationSize();
nds.TopLevel = false;
nds.FormBorderStyle = ... // you may want to set this to none
nds.Dock = ... // you may want to set this to fill
f.Controls.Add(nds);
nds.Show(); // Open another form on Modal Dialog
f.ShowDialog(); // Open Modal window
Related Topics
How to Detect the Language of a String
Why Cannot C# Generics Derive from One of the Generic Type Parameters Like They Can in C++ Templates
How to Connect to an .Mdf (Microsoft SQL Server Database File) in a Simple Web Project
How to Find and Replace Text in a File
How to Fix a .Net Windows Application Crashing at Startup with Exception Code: 0Xe0434352
Access a Remote Directory from C#
Best Way in .Net to Manage Queue of Tasks on a Separate (Single) Thread
Playing a Mp3 File in a Winform Application
Why Does "Int[] Is Uint[] == True" in C#
Parameterized Queries VS. SQL Injection
What Is the Use of Enumerable.Zip Extension Method in Linq
How to Deserialize a JSON Property That Can Be Two Different Data Types Using JSON.Net
Mail Sending with Network Credential as True in Windows Form Not Working
Properly Draw Text Using Graphicspath
Why Are Properties Without a Setter Not Serialized
Can't Add Script Component Because the Script Class Cannot Be Found