Mimicking a Dialog Form using a Panel
Hi,
I'm sorry if I'm missing something obvious here, but I haven't had my coffee yet so I'm not really awake yet;)
I'm developing an application that should run on a 'kind of' mobile device. It's not exactly a mobile device (hence I'm not developing in the mobile framework, just winforms), but I can't use various Forms either.
Right now I am working on a proof of concept, and I simulated the mobile device simply with a UserControl that has a fixed size. Everything needs to happen on that UserControl, and I cannot display any other forms.
However, I now need a 'Dialog Form' to let the user enter some data (mainly text but it doesn't really matter). What I'm doing now is simply showing a Panel with a TextBox, OK button and Cancel button. I bring that panel to the front, hiding the rest of the application, when required. The different Panels (there's also one for a CheckBox, ComboBox, and the main application is also on a Panel) are all on a 'PanelContainer' UserControl I made, and I can switch panels simply by specifying their 'key' (a string such as "TEXT", "CHECK", "COMBO" etc). So I can display the textbox panel by simply doing
Code:
panelContainer1.SelectedKey = "TEXT"
That brings the textbox panel to the front.
What I want now is that I can 'show' the panel as if it were a Dialog form. That means that the code 'waits' until the user has entered his text and either clicked OK or Cancel. Then I could use it like this
Code:
' Show the panel here
Dim result As DialogResult = panelContainer1.Panels("TEXT").ShowDialog()
' and immediately use the result (the code won't come here until the user has selected ok or cancel)
If result = DialogResult.OK Then
'...
End If
Right now I cannot do that.. The code continues right away after the panel has been shown, and the only other option (I think) is to let the panel raise an event when the user is done with it, so that I can handle the event. The problem with that is that I would then have to check in the event handler what he was editing, where the result should go, etc... It would be so much better if I could just use the panel as if it were a dialog form... But I have no idea how to do that!
Is it even possible?
I suppose I should give the panel a ShowDialog method:
Code:
Public Class TextboxPanel
Inherits SwitchPanel ' switchpanel is the base class with OK/Cancel buttons and inherits Panel
Public Function ShowDialog() As DialogResult
Me.BringToFront() 'show it
' wait for user input..?
Return ...? result?
End Function
End Class
I'm not sure if I'm missing something REALLY obvious here... But I've never had the need to do this as I can normally just use a dialog form :p
Thanks!
Re: Mimicking a Dialog Form using a Panel
Excuse me if I'm misunderstanding your problem, but I don't see why you don't want to raise an event -- in particular, a custom event.
You define an EventArgs with properties to carry any kind of information, for example:
vb.net Code:
Public Class SwitchPanelEventArgs
Inherits EventArgs
Public Property Text() As String
End Class
and make a custom event in your SwitchPanel class like this:
vb.net Code:
Public Event DialogEndEvent(ByVal e As SwitchPanelEventArgs)
'raise the event:
Private Sub OKButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles OKButton.Click
RaiseEvent DialogEndEvent(New SwitchPanelEventArgs With {.Text = MyTextBox.Text})
Me.Hide()
End Sub
Then you handle the event on your main form:
vb.net Code:
Private Sub TextBoxPanel1_DialogEndEvent(ByVal e As SwitchPanelEventArgs) Handles TextBoxPanel1.DialogEndEvent
MessageBox.Show(e.Text)
End Sub
How about that? BB
Re: Mimicking a Dialog Form using a Panel
I know I can do that, but there's one problem with that. The panels ("forms") I'm showing are just 'generic' panels, they can be used to edit just about anything. I edit a boolean value (any boolean value) from the database with a checkbox, a string value with a textbox, etc.
What I do is basically this:
1. The user clicks an item in some kind of listbox
2. This item contains information about the table and the fields it came from. So for example, an item could have a TableName of "PERSONS" and a fieldname of "AGE", then the listbox item would show a label ("Age:") and a value (the value in the database under the "AGE" field in the "PERSONS" table).
So, in order to be able to edit the item (I have to save it back to the database), I need to know which item I was editing. I can store that in some private field or something, but I'd much rather keep it in the same spot, as I could with a dialog form.
So I'm not saying I don't know of any other methods to do this, it's just that it would be much neater if I could do it like this :)
Re: Mimicking a Dialog Form using a Panel
I take it you show and hide the panel (rather than instantiating and disposing it). If so, the fields of any control in the panel's Controls collection will persist in the same way as they were on a form. Isn't that what you are doing? BB
Re: Mimicking a Dialog Form using a Panel
If you have a panel with an OK and Cancel button can't you key off those events? If the panel covers everything behind it, it will be forced to wait for the OK or Cancel. Or you can disable anything visible behind the panel, effectively 'waiting' for the click event on the buttons. Am I following you?
Re: Mimicking a Dialog Form using a Panel
Quote:
Originally Posted by
MarMan
If you have a panel with an OK and Cancel button can't you key off those events? If the panel covers everything behind it, it will be forced to wait for the OK or Cancel. Or you can disable anything visible behind the panel, effectively 'waiting' for the click event on the buttons. Am I following you?
No, you aren't following I think. The problem is that the ShowDialog method doesn't wait for the user to input anything. It returns immediately. In a dialog form, it does not return until the user sets the DialogResult property or closes the form.
Re: Mimicking a Dialog Form using a Panel
Why do you have to use 'ShowDialog'? Why not just Visible=True?
Re: Mimicking a Dialog Form using a Panel
Because Visible=True does not wait for user input either. They are not blocking calls, but return immediately. Haven't you ever used ShowDialog before? If you have, try replacing ShowDialog by just Show and see what happens.
Re: Mimicking a Dialog Form using a Panel
I am definately not following you. Must be a Friday morning thing.
I've used panels for dialogs before, many times. I make them visible and disable anything behind them. The only controls that are active are controls on the panel. The panel sits there and covers everything up until the code in the click event executes. Obviously I'm missing something here.
No I haven't used ShowDialog.
Re: Mimicking a Dialog Form using a Panel
Nick, can you use .net reflection to see how the showdialog method is implemented?
Re: Mimicking a Dialog Form using a Panel
So the custom ShowDialog method on the panel will get called, and you don't want it to return until the user has pressed something, right?
That's going to be a bit tricky to do, since a function normally plods on to the end, and returns, unless it does something like show a form using ShowDialog. Not many other things pause execution of the thread, but a few things do.
Suppose your ShowDialog method launched a thread that dealt with all the interactions of the form, and called Join on that thread from the main thread. That could be made to work with some difficulty. The main thread would appear to pause until the other thread ends, but you would need that other thread to keep running until it was done. That would leave you with almost the same problem that you have now. One way to handle it would be to have the second thread polling continually, but that's little better than a busy wait.
Another alternative would be to use a Mutex. Fire off that other thread, which would do nothing other than grab the mutex, while the UI thread (in the ShowDialog method) would wait on that Mutex. This would allow the worker thread to wait around for user input before releasing the Mutex and ending. It would be the release of the Mutex that would free the UI thread to continue, which would cause ShowDialog to return, and so on.
Seems overly complicated when I think about it, but in practice, it might actually be easier. The UI thread would be spawning something that would do all the work, and would just be waiting for that something to complete its work. The only thing that comes to mind that allows one thread to just be paused until released, is something like a flow control object such as a Mutex.
Re: Mimicking a Dialog Form using a Panel
Well I was really hoping there might be a simpler answer. Stanav, I'm pretty sure the way ShowDialog works is embedded into windows. I've read something about the new form doing its own message loop or something. I'm pretty sure there's no way to do that in .NET at least not directly.
I think I will stick with the events approach. I do still have a question about that... Right now, instead of a ShowDialog method I just made a ShowPanel method, which shows the appropriate panel with the appropriate data and returns that panel. Then I use AddHandler to attach the OkButtonClicked and CancelButtonClicked events. In those handles however, I immediately use RemoveHandler again to remove the events. Is that ok?
This shows the panel ('fl' is an instance of the listbox item I mentioned (I think) and contains the data to fill the panel with, and also which panel to show)
vb.net Code:
Dim panel As Controls.SwitchPanels.ucSwitchPanel = mfc.SwitchPanelContainer.ShowPanel(fl)
If panel IsNot Nothing Then
AddHandler panel.OkButtonClicked, AddressOf SwitchPanel_OkButtonClicked
AddHandler panel.CancelButtonClicked, AddressOf SwitchPanel_CancelButtonClicked
End If
Then in these handles, I do this:
vb.net Code:
Private Sub SwitchPanel_OkButtonClicked(ByVal sender As Object, ByVal e As EventArgs)
Dim panel = DirectCast(sender, Controls.SwitchPanels.ucSwitchPanel)
' Get the new data
panel.FormListItem.Data = panel.Value
' Save it
_FormManager.UpdateData(panel.FormListItem)
panel.FormListItem.DataListItem.DataId = panel.FormListItem.DataId
' Load the list again, with the updated data
_DontUpdateHistory = True
mfc.DataSource = _FormManager.LoadFromDatalistItem(panel.FormListItem.DataListItem)
_DontUpdateHistory = False
' Show the list
mfc.SwitchPanelContainer.SelectedKey = "LIST"
' And remove the handler...
RemoveHandler panel.OkButtonClicked, AddressOf SwitchPanel_OkButtonClicked
End Sub
Private Sub SwitchPanel_CancelButtonClicked(ByVal sender As Object, ByVal e As EventArgs)
Dim panel = DirectCast(sender, Controls.SwitchPanels.ucSwitchPanel)
mfc.SwitchPanelContainer.SelectedKey = "LIST"
RemoveHandler panel.CancelButtonClicked, AddressOf SwitchPanel_CancelButtonClicked
End Sub
I'm not actually sure I even need to use RemoveHandler (I'm afraid I don't use it very often, probably not often enough!) but I don't think it can hurt... Can it?
Re: Mimicking a Dialog Form using a Panel
If you add a handler when you show the panel, you'll need to remove it again when you hide it. Otherwise, next time you show the panel it will perform the handler code twice, then three times and so on. Instead, you could just use the Handles clause. BB
Re: Mimicking a Dialog Form using a Panel
Yeah, that's why I used RemoveHandler in the first place. I just wasn't sure whether I could do that in the method handler itself. And I can't use the Handles clause as I only get the panel from the ShowPanel function, so I don't know it during design-time.
Re: Mimicking a Dialog Form using a Panel
I don't see them used very much, and I certainly havnt used them, but maybe you can hijack a method that normally wouldnt halt control using Extention Methods?
http://en.wikipedia.org/wiki/Extension_method
just a crazy idea