Mono Gtk.Dialog returning object as response - c#

I am trying to write a simple form application with mono Gtk# but am already stuck in the beginning I create a Dialog form inherits from Gtk.Dialog. The dialog form for collection basic information and returning these information as an object to main window or trigger some event to main window so it can do what it suppose to do in this case bind the data a TreeView control (which is another story). These are what I have tried so far;
Dialog code
public partial class MyDialog : Gtk.Dialog
{
public MyDialog ()
{
this.Build ();
}
protected void OnButtonOkClicked (object sender, EventArgs e)
{
int portNumber = 0;
iint.TryParse (spnPort.Text, out portNumber);
var myObj = new MyObj ();
myObj.Username = txtUsername.Text;
myObj.Password = txtPassport.Text;
// did not work as ParentWindow is a Gdk.Window
//(this.ParentWindow as MainWindow).AddObj(myObj);
//Also did not work because there is no response related method
//or property in the Dialog please read below code block this will make more sense
//this.OnResponse(myObj);
}
}
MainWindow Code to call dialo
protected void OnAddActionActivated (object sender, EventArgs e)
{
MyDialog s = new MyDialog();
s.Run();
s.Response += HandleResponse;
}
void HandleResponse (object o, ResponseArgs args)
{
//as this event has args.Args and args.RetVal I thought one would do what I wanted
//maybe I am using them all wrong
}
I appreciate it if some one can explain what is Gdk.Window is and what it is doing under Gtk control.

Just store the object you want to return in your dialog object, and provide access to it using a property. Don't forget to check whether the user pressed the cancel button (if you have one), conveniently by examining the return value of Run().
For an example see the sample code for the stock FileChooserDialog in the official documentation.

Related

How to fix an instance when trying to access a button of another winform?

hello i have this code here (Owner as ReadBarCodeInMenu).btnContainerInquiry.Enabled = true; it keeps me throwing an instance whenever i tried to access a button of another page it tried this code in a test 2 forms and it works perfectly fine but when i put it in system i gave me an error.Please help me
edit:
form ReadBarCodeInMenu
private void btnContainerInquiry_Click(object sender, EventArgs e)
{
inquiry.Owner = this;
btnContainerInquiry.Enabled = false;
}
form ContainerInquiry
private void logoutBtn_Click(object sender, EventArgs e)
{
(Owner as ReadBarCodeInMenu).btnContainerInquiry.Enabled = true;
error// {"Object reference not set to an instance of an object."}
close.
}
this is how i access the bottom of an another form if i do this in new 2 form it works with no error.
Assuming that you open form ContainerInquiry from withing form ReadBarCodeInMenu, you can do the following. In form ContainerInquiry, add a parameter to the constructor, accepting a reference to the first form
private ReadBarCodeInMenu _readBarCodeInMenu;
public ContainerInquiry(ReadBarCodeInMenu readBarCodeInMenu)
{
InitializeComponent();
_readBarCodeInMenu = readBarCodeInMenu;
}
private void logoutBtn_Click(object sender, EventArgs e)
{
_readBarCodeInMenu.btnContainerInquiry.Enabled = true;
}
Also, change the accessibility of btnContainerInquiry from private to internal (or public).
Then in form ReadBarCodeInMenu
// Pass a reference of ReadBarCodeInMenu to ContainerInquiry.
var frm = new ContainerInquiry(this);
...
You cannot access the UI from another thread than the UI thread. If try to do so, you are getting the exception
Cross-thread operation not valid: Control 'btnContainerInquiry' accessed from a thread other than the thread it was created on.
In this case you must invoke the control or form you are accessing. This mechanism passes a delegate to the right thread and executes it there.
var btn = _readBarCodeInMenu.btnContainerInquiry;
if (btn.InvokeRequired) {
btn.Invoke(new Action(() => btn.Enabled = true));
} else {
btn.Enabled = true;
}
You could also create an extension method that automates this process as shown here: https://stackoverflow.com/a/12179408/880990

Return value without close the window wpf

I want to have a return value from my WPF window without close it.
I have an DLL with WPF usercontrol inside, I call it from my DLL code.
I have to call it, it returns me datas, then I send it datas.
But I don't want to create two different instance of the same window.
My code :
MP.UserControl1 a = new MP.UserControl1();
a.ShowDialog();
if (a.DialogResult.HasValue && a.DialogResult.Value == true)
{
a.Hide();
InitialDatas = a.inputData;
}
else
return 0;
Then I elaborate InitialDatas
And now I want to call a method inside my "a", and show it again, without create a new window.
Code :
a.SetValue(result, off1, InitialDatas);
a.ShowDialog();
I got error message : Cannot set visibility or call Show, ShowDialog or EnsureHandle after a window has been closed
Is it possible to solve?
I would solve this with an event model. You could do the following:
Create an event in the Form
Create an event handler in the caller
Subscribe to the event and do your logic
The called form:
namespace MyApplication
{
public delegate void MyEventHandler(object source, EventArgs e);
public class MyForm : Form
{
public event MyEventHandler OnInitialData;
private void btnOk_Click(object sender, EventArgs e)
{
OnInitialData?.Invoke(this, null);
}
}
}
In your other Form:
MP.UserControl1 a = new MP.UserControl1();
a.OnInitialData += UCA_OnInitialData;
private void UCA_OnInitialData(object sender, EventArgs e)
{
MP.UserControl1 a = sender as MP.UserControl1;
a.SetValue(result, off1, a.inputData);
}
a.ShowDialog();
As the error message states, you cannot close the window and then open it again.
Instead of closing a window you could hide it by calling the Hide() method and then showing it again by calling the Show() method.
But since the ShowDialog() method doesn't return until the window has been closed, this won't work for a dialog window though. If you require a modal window, you will have to create a new instance of the window and open this one. This shouldn't really be an issue though.
So I guess the answer to your question is simply no. You cannot re-open a closed dialog window.

gtk# thread for window

I'm building a GUI application with C# and gtk#. I've encountered an issue recently and was looking for the best solution to this problem:
I have a modal window that pops up for the user to enter a number. This window is a separate window accessed from my main window and it's set up like this:
public class MainWindow()
{
public NumberEntry numEntry;
Whenever I need numerical input from the user, I call ShowAll() on the public Window property of NumberEntry like:
numEntry.win.ShowAll();
And all of this works fine. Afterwards, to get the value they entered, I call:
int entered = numEntry.valueEntered;
The issue is obviously that code continues executing immediately after the ShowAll() line is finished, and numEntry.valueEntered is always 0. What I'd like to do (and have been trying to do), is to suspend the main thread, and open up the number entry window in a second thread, and join back to the main thread when this is complete. Suspending the main thread seems to prevent GUI changes making the program freeze when I try to open the number entry window. I'd also like to avoid callback methods if at all possible, seeing as how this would get rather complicated after awhile. Any advice? Thanks!
Seems like when GTK window is closed all its child controls are cleared. So to get the result from the custom dialog window you may do the following (I am not gtk guru but its works for me):
1. Create a new dialog window with your controls (I used Xamarin studio). Add result properties, OK and Cancel handlers and override OnDeleteEvent method:
public partial class MyDialog : Gtk.Dialog
{
public string Results {
get;
private set;
}
public MyDialog ()
{
this.Build ();
}
protected override bool OnDeleteEvent (Gdk.Event evnt)
{
Results = entry2.Text; // if user pressed on X button..
return base.OnDeleteEvent (evnt);
}
protected void OnButtonOkClicked (object sender, EventArgs e)
{
Results = entry2.Text;
Destroy ();
}
protected void OnButtonCancelClicked (object sender, EventArgs e)
{
Results = string.Empty;
Destroy ();
}
}
2. In your main window create a dialog object and attach to its Destroyed event your event handler:
protected void OnButtonClicked (object sender, EventArgs e)
{
var dialog = new MyDialog ();
dialog.Destroyed += HandleClose;
}
3. Get the results when dialog is closed:
void HandleClose (object sender, EventArgs e)
{
var dialog = sender as MyDialog;
var textResult = dialog.Results;
}
If you whant you also may specify a dialog result property and etс.

Making two boxes equal each other

I am trying to make a text box (UPC_txtBox4) self populate to equal the same value of UPC_txtBox2. The two text boxes are on separate forms but I feel there should be a way to link the two.
If form1 is responsible for navigating to form2, then you can pass the value on the query string from form1 using a URL similar to the following:
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack)
{
Response.Redirect(Request.ApplicationPath + "/Form2.aspx?upc=" + UPC_txtBox2.Text, false);
}
}
then in form2 code:
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
// Assuming this field is an asp.net textbox and not an HTML input
UPC_txtBox4.Text = Request.QueryString["upc"];
}
}
Alternatively, you could store the value in session state, assuming that you are using sessions.
CORRECTION: Seeing as you are using WebForms, not WinForms as I had assumed, the below is irrelevant. I'll leave it just incase it helps someone else.
You should just create a method on the form that needs to be updated, then pass a reference when of that form to the newly created form.
This won't work if either form is a dialog (as far as I know).
So:
Form that has the textbox that will be directly edited.
private Form formToUpdate;
public void OpenForm(Form _formToUpdate)
{
formToUpdate = _formToUpdate;
txtBlah.TextChanged += new EventHandler(OnTextChanged);
this.Show();
}
private void OnTextChanged(object sender, EventArgs e)
{
formToUpdate.UpdateText(txtBlah.Text);
}
Form that is to be dynamically updated:
delegate void StringParameterDelegate (string value);
public void UpdateText(string textToUpdate)
{
if (InvokeRequired)
{
BeginInvoke(new StringParameterDelegate(UpdateText), new object[]{textToUpdate});
return;
}
// Must be on the UI thread if we've got this far
txtblah2.Text = textToUpdate;
}
Note: this is untested (although it should work), and largely pseudo code, you'll need to tailor it to your solution obviously.

Add listview items from other form (using objects)

I want to get some data to fill a listview control, but this data it's determined in other form. This is what I code in form1 (Nuevo_Credito):
private void combo_cliente_SelectionChangeCommitted(object sender, EventArgs e)
{
Credito_Grupo ventana = new Credito_Grupo(combo_cliente.SelectedItem);
ventana.ShowDialog();
}
public void AgregaIntegrantes(string id, string nombre, string monto)
{
ListViewItem elem = new ListViewItem(id);
elem.SubItems.Add(nombre);
elem.SubItems.Add(monto);
listView_integrantes.Items.Add(elem);
}
I'm invoking form2 (Credito_grupo) as show dialog window, then I want to retrieve some values and pass them to Form1 using the public method "AgregaIntegrantes". So in form2 I did the following:
public Credito_Grupo(dynamic item)
{
this.id = item.IDCliente;
this.nombre = item.NomComp;
InitializeComponent();
}
private void Credito_Grupo_Load(object sender, EventArgs e)
{
text_nombre.Text = this.nombre;
}
private void button_AgregaCliente_Click(object sender, EventArgs e)
{
Nuevo_Credito obj = new Nuevo_Credito();
obj.AgregaIntegrantes(id.ToString(), nombre, text_monto.Text);
this.Close();
}
When the event button_AgregaCliente_click is triggered I need to add the data to listview in form1 using the method described above, but none data is added. I found a solution using delegates here 3077677, is there an approach using objects?
You have an error in button_AgregaCliente_Click method (the last one in the listing). You create a new Nuevo_Credito form there, and pass the data to listview. It looks OK. But this newly created Nuevo_Credito form does exist only in the local variable, so then you throw it away without displaying it when button_AgregaCliente_Click finishes.
I think you need to delete this line: Nuevo_Credito obj = new Nuevo_Credito();
You need to get your real Nuevo_Credito form, not create a new one here.
You can send this from your Nuevo_Credito to the constructor of the Credito_Grupo form. Then you can use it to call back to the original Nuevo_Credito. This approach is based only on objects, and not delegates. As you wanted. :-)

Categories