A combination of winforms' controls as a prefab? - winforms

In our winforms application we often have a situation where the same panel is used in different forms. Right now I simply copy the code and the designer elements from form to form but that is obviously a terrible practice.
So I thought of making a class that could be easily added to a different form as a "component". The only problem is to be able to prototype and maintain this panel in the visual designer in such a way that if I want to change the panel's appearance in the future it gets changed for every class instance I created.
For instance I have a panel that provides search functionality:
Alongside with the code for click/textChanged events. I want to encapsulate it in a class, which I would be able to instantiate and initialize in any form's constructor to instantly add these controls (alongside events) into that form. Now it is not necessary for me to see the controls in the designer of the recepient form, however, I need to be able to see them in the designer somewhere in order to modify them if I would ever require that.
And if I do modify the appearance somehow (for instance add an extra button) these controls instantly change across the entire project, everywhere I instantiated the class.
I do know that all this can easily be done just creating a new form and encapsulating everything in it, I just wonder if it can be done for a group of controls instead.

You just described the perfect use of a User Control. It's easy to use and direct.
First Add a user COntrol to the project:
Then add the desired controls on the user control:
Build the project and you will see the UserControl on the toolbox:
Add them to the form as a standard control:
If you change the code for the user control (in this case adding a button click handler) uit will affect all the intances of that user control:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = "Button Clicked"
End Sub
Note: If you have the Control in another project on the same solution, make sure you build that project too if you make any change.

Related

Passing Parameters from one view model to another in wpf

As I continue to adapt to the new world of wpf and mvvm I find myself with another problem which is proving to be a little vexing.
In windows forms if I needed a new form to take a parameter I simply passed the information that I needed to that form's constructor. As Winforms is essentially a code behind model anyway this wasn't an issue.
I now find myself with a MainWindow (controlled by MainWindowViewModel) and a Login (controlled by LoginViewModel) which is shown as a dialog first. I have sorted the issue of the missing dialog result and I can get the main window to show after closing the login dialog.
The login dialog is shown and responded to in the Application startup with the following code;
dim dlg As New Login
If dlg.ShowDialog() = True Then
Else
Current.Shutdown(0)
End If
and I use the use the following in the code behind of the login window to take care of showing the main window when the login dialog closes;
Public Sub New
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Application.Current.ShutdownMode =ShutdownMode.OnExplicitShutdown
End Sub
Protected Overrides Sub OnClosed(e As EventArgs)
MyBase.OnClosed(e)
Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose
End Sub
Now the Mainwindow already knows that it's datacontext is MainWindoViewModel because I set that up when designing it with blend, so how do I pass any parameters that I want to pass from the LoginViewModel to the MainWindowViewModel?
I can read c# but would prefer vb if possible. I know that this is something that I will want to be doing often so if there is a generic way to do this then that's the way I'd like to go.
Thanks
Mvvm frameworks generally implement some kind of messaging system to allow data to be moved between viewmodels or sometimes between viewmodel and view.
You can look at the way messaging is handled in some of the more popular frameworks such as MvvmLight or MvvmCross. It's usually just like an event that uses a weak reference to prevent tight coupling, so you can register for a type of message and then from another viewmodel you publish a message to any registered listeners.
So you will either need to implement your own kind of messenger, or now might be a time to look at starting to use a third party framework, unless you have specific reasons for avoiding this.

Tool to know Windows Form Application's Form fields

I am working on a WinForm Application.
The Form has many fields/components but is poorly built.
for example a field is used as user name on one case and used as folder path on the other case. Code is quite poorly maintaned.
Is is possible that when i run the application and GUI appears, i can use a tool like 'spy++' which can show me 'names' of the components (not ids). For instance the name of a button or name of a label.
Or if i can use SPY++ for 'names' please tell me?
I would solve the problem by adding a ToolTip control to your form and iterating over each control and adding a Tool Tip message to each control that is the name of the control.
First, add a ToolTip object to your form (from the Tools section of the designer.) You can rename it, but for the sake of my demo, I left it as the default name toolTip1.
Next, add a method similar to the one I'm posting below to the code page of your form. (I'm assuming this is for C# but the code is simple and can easily be modified for VB or C++).
public void AddNameToToolTip(Control c)
{
toolTip1.SetToolTip(c, c.Name);
foreach (Control child in c.Controls) AddNameToToolTip(child);
}
Finally, from within the Form constructor, add the following line of code after the call to InitializeComponent().
AddNameToToolTip(this);
This will add a ToolTip message to each control in your form. All you should have to do is hover your mouse over each control and the ToolTip will pop up a message after a second or two displaying the name of the underlying control.
Alternatively, you can recursively adding a MouseHover event to each control and when the event is fired, write the name of the control to the debugger. This would also work if you are already using a ToolTip control within your form.

How can I add additional bindable visual state groups to a button?

I need to extend a button control to add some additional, bindable, visual states.
What I would like to create is an additional boolean property, to bind to, that will create a simple visual state change on the button. For this example, it could just be an additional border which changes colour according to the boolean value.
All the existing button behaviour should be entirely seperate from this new set of states.
Can this be done?
This can certainly be done. Here's a post that walks you through the steps you'll need to take, and includes additional information for extending the control with properties (besides just those to hold state) that show up in the final control. The pieces you'll need are:
A class that derives from Button (your custom control class)
A default style for this control (which goes in /themes/generic.xaml). You can start off with Button's generic style and add your states to it.
A dependency property that holds your boolean value
A new VisualStateGroup that holds your two new states
Some code in your class that glues together changing states with the boolean value you've defined, presumably resulting from user interaction, etc.
You may find it's easier to edit the visual state in Blend, depending on how sophisticated your transitions will be, etc.

Loosely couple a modal dialog - is this possible?

I have a winforms custom UI control library which contains a control for displaying modal dialogs Picture-in-Picture.
This custom control receives as a parameter a pointer to the control which has initiated it's display. So they are tied together. This allows the control to be modally displayed over the window which launched it.
Dim f As New PiPCustomDialog 'this form wraps another form PictureInPicture style
f.FormToLoad = New PrintOptions() 'this is the form the user will interact with
f.Owner = Me 'used to determine the size of PiPCustomDialog
Dim dr As DialogResult = f.ShowDialog(Me) 'shows PiPCustonDialog coating, f's OnLoad event initiates display of FormToLoad centered within.
The fact that this control requires f.Owner to be set is what is stinky. User32.dll has a function GetActiveWindow() which would maybe allow the control to be more self-sufficient.
Anyone out there who would like to teach this old dog a new trick? I want to learn a better way.
I'll use this solution for now:
Remove any validation that requires
owner to be set before showing the
form modally.
if owner isn't set inside the class that is transparent cover
(first form) - do a system call into
GetActiveWindow to get owner so the size of the window can be set.

Displaying controls on an alpha-blended form

I tried the Visual C# Kicks code for an alpha-blended form. This works (as soon as I remove the TransparencyKey property); that is, I can use the W3C's PNG alpha test image and see other windows underneath, but makes all controls on the form invisible. Presumably, they simply aren't painted, as OnPaint is overridden. I tried calling the superclass's OnPaint:
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
UpdateFormDisplay()
MyBase.OnPaint(e)
End Sub
, but this didn't change anything. (Calling MyBase.OnPaint first doesn't make any difference either.)
Unfortunately most articles about alpha-blended forms focus on pure splash screens without any controls on them — but we need a panel which first shows sign-in fields, then a progress bar.
The controls, by the way, do not need transparency; it's only on the outer edges that the PNG's transparency truly matters. So faking this by adding another form on top of this all (with the two always moving in tandem) might suffice, but I'd prefer a smoother solution.
Try putting this in your form ctor after InitializeComponents();
base.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);

Resources