Dynamic creation of forms & containers - c#

I'm very new to C#.
Below is a code that I'm trying to create forms and containers within the code; but I've problems with it.
I start with a new Windows Forms Application template.
I change the Program.cs file a little, so that I'd be able to create the FormMain dynamically.
When the lines Container.Add(BtnClose) and BtnClose_Setup() in FormMain.cs are commented, the code compile and run. However, there are still some weird results in the program.
(a) The form FormMain is supposed to show up at (20, 20) (upper left corner), as the FormMain_Setup says; but when I run the app, though width & height settings show up as expected (800, 600), the upper left corner changes every time (does not stick to 20, 20).
(b) The esc key works as expected and closes the form and application.
When the lines Container.Add(BtnClose) and BtnClose_Setup() in FormMain.cs are not commented, the code compile but VS sends me a message when it's run: "An unhandled exception of type 'System.TypeInitializationException' occurred in mscorlib.dll"
Can someone tell me what I'm doing wrong?
Program.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test {
static class Program {
public static FormMain FormMain = new FormMain();
[STAThread]
static void Main() {
Application.Run(FormMain);
}
}
}
FormMain.cs file:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test {
public partial class FormMain : Form {
Button BtnClose = new Button();
public void BtnClose_Setup() {
BtnClose.Text = "Ok";
BtnClose.Top = 500;
BtnClose.Left = 700;
}
public void FormMain_Setup() {
Top = 20;
Left = 20;
Width = 800;
Height = 600;
KeyDown += FormMain_KeyDown;
//Container.Add(BtnClose);
//BtnClose_Setup();
}
void FormMain_KeyDown(object sender, KeyEventArgs e) {
if(e.KeyCode == Keys.Escape) {
Close();
}
}
public FormMain() {
InitializeComponent();
FormMain_Setup();
}
}
}

Call Controls.Add(BtnClose); instead of Container.Add(BtnClose);.
As for fixing the form position: set StartPosition = FormStartPosition.Manual; property.
To properly close the form on Esc, override ProcessCmdKey method:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Escape)
{
Close();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}

By default a forms StartPosition is set to WindowsDefaultLocation. You need to set it to Manual; either in the designer or in the code.
To add a control to a form, you want to add it to the form's Controls collection, not the Container.
Also, if you want the form to continue to get KeyDown events after the button is added you need to set KeyPreview to true.
public void FormMain_Setup()
{
StartPosition = FormStartPosition.Manual;
KeyPreview = true;
Top = 20;
Left = 20;
Width = 800;
Height = 600;
KeyDown += FormMain_KeyDown;
Controls.Add(BtnClose);
BtnClose_Setup();
}

Related

ContextMenuStrip.Show not working half the time

tl/dr: Every second time I call ContextMenuStrip.Show, it doesn't show.
I am building an application that runs in the background but displays a drop-down menu on the mouse cursor when the user hits a specific hotkey.
If the application has focus, this works 100% of the time. If another application has focus (this is my main use case) it fails exactly 50% of the time. Specifically, the first hotkey press works, but once you select an item from the menu (which triggers a short function), the next hotkey press does not display the menu. If you keep pressing the hotkey without clicking the menu, the menu keeps popping up at the cursor position. If you switch back to the application, the menu appears every time.
I am fairly new to coding, but I have simplified the code such that the hotkey press does nothing other than run a single line of code (ContextMenuStrip.Show), and I have watched in the debugger and that line does get hit, and all the variables look the same to me on the presses that do and don't work.
EDIT: This is the simplest version of the code I could make. Please excuse any weirdness. I'm new to coding and am probably doing unrelated strange things!
To reproduce, run the program, switch to another window, press Ctl-Q to bring up the menu, select an item, press Ctl-Q again and the menu should fail to show.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;
using System.Runtime.InteropServices;
namespace Bug
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Register hotkey
int UniqueHotkeyId = 1;
int HotKeyCode = (int)Keys.Q;
Boolean F9Registered = RegisterHotKey(
this.Handle, UniqueHotkeyId, 2, HotKeyCode
);
myPopupMenu.menu = myPopupMenu.BuildMenu();
}
// Stuff that makes the hotkey work
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
protected override void WndProc(ref Message m)
{
// Catch when a HotKey is pressed !
if (m.Msg == 0x0312)
{
int id = m.WParam.ToInt32();
if (id == 1)
{
// Show Menu on hoteky press
myPopupMenu.ShowMenu();
}
}
base.WndProc(ref m);
}
public PopupMenu myPopupMenu = new PopupMenu();
}
public class PopupMenu
{
public ContextMenuStrip menu { get; set; }
public ContextMenuStrip BuildMenu()
{
ContextMenuStrip menu = new ContextMenuStrip();
ToolStripMenuItem item;
ToolStripMenuItem submenu;
submenu = new ToolStripMenuItem();
submenu.Text = "submenu";
item = new ToolStripMenuItem("item", null, MenuClick);
submenu.DropDownItems.Add(item);
menu.Items.Add(submenu);
return menu;
}
public void ShowMenu()
{
menu.Show(Cursor.Position);
}
public void MenuClick(object sender, EventArgs e) { }
}
}
Change
ContextMenuStrip menu = new ContextMenuStrip();
To
ContextMenuStrip menu = new ContextMenuStrip { AutoClose = false };
And your example now works 100% of the time on my end (both focused and not focused).
Why, I'm not quite sure. Just used an automated tool to rapidly change things until desired behavior occurred.

Message box in UWP not working

Please help me, I have ran into a problem. I'm new in UWP coding
problem : I have build a simple application which consists of a button. When the button is pressed it will display a message
Error : Cannot find typre System.Collections.CollectionBase in module CommonLanguageRuntimeLibrary
Here is my code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Windows.MessageBox;
using System.Windows.Forms;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace App1
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("HI");
}
}
}
There is no MessageBox in UWP but there is a MessageDialog:
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Popups;
using System;
namespace App1
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
var dialog = new MessageDialog("Hi!");
await dialog.ShowAsync();
}
}
}
I strongly recommend you to use a separate, function to display a popup message.
UWP uses the namespace Windows.UI.Popups and not System.Windows.MessageBox, since it's only used for Win32 or WinForms applications
Here's a good way to display your desired message:
// Other namespaces (essential)
...
// Required namespaces for this process
using Windows.UI.Popups;
using System.Runtime.InteropServices;
namespace PopupMessageApp
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
// I will only comment those that are not obvious to comprehend.
private async void ShowMessage(string title, string content, [Optional] object[][] buttons)
{
MessageDialog dialog = new MessageDialog(content, title);
// Sets the default cancel and default indexes to zero. (incase no buttons are passed)
dialog.CancelCommandIndex = 0;
dialog.DefaultCommandIndex = 0;
// If the optional buttons array is not empty or null.
if (buttons != null)
{
// If there's multiple buttons
if (buttons.Length > 1)
{
// Loops through the given buttons array
for (Int32 i = 0; i < buttons.Length; i++)
{
/* Assigns text and handler variables from the current index subarray.
* The first object at the currentindex should be a string and
* the second object should be a "UICommandInvokedHandler"
*/
string text = (string)buttons[i][0];
UICommandInvokedHandler handler = (UICommandInvokedHandler)buttons[i][1];
/* Checks whether both variables types actually are relevant and correct.
* If not, it will return and terminate this function and not display anything.
*/
if (handler.GetType().Equals(typeof(UICommandInvokedHandler)) &&
text.GetType().Equals(typeof(string)))
{
/* Creates a new "UICommand" instance which is required for
* adding multiple buttons.
*/
UICommand button = new UICommand(text, handler);
// Simply adds the newly created button to the dialog
dialog.Commands.Add(button);
}
else return;
}
}
else
{
// Already described
string text = (string)buttons[0][0];
UICommandInvokedHandler handler = (UICommandInvokedHandler)buttons[0][1];
// Already described
if (handler.GetType().Equals(typeof(UICommandInvokedHandler)) &&
text.GetType().Equals(typeof(string)))
{
// Already described
UICommand button = new UICommand(text, handler);
// Already described
dialog.Commands.Add(button);
}
else return;
}
/* Sets the default command index to the length of the button array.
* The first, colored button will become the default button or index.
*/
dialog.DefaultCommandIndex = (UInt32)buttons.Length;
}
await dialog.ShowAsync();
}
private async void MainPage_Load(object sender, EventArgs e)
{
/* Single object arrays with a string object and a "UICommandInvokedHandler" handler.
* The ShowMessage function will only use the first and second index of these arrays.
* Replace the "return" statement with a function or whatever you desire.
* (The "return" statement will just return and do nothing (obviously))
* (Edit: Changed 'e' to 'h' in UICommandInvokedHandler's)
*/
object[] button_one = { "Yes", new UICommandInvokedHandler((h) => { return; }) };
object[] button_two = { "No", new UICommandInvokedHandler((h) => { return; }) };
/* Object arrays within an object array.
* The first index in this array will become the first button in the following message.
* The first button will also get a different color and will become the default index.
* For instance, if you press on the "enter" key, it will press on the first button.
* You can add as many buttons as the "Windows.UI.Popups.MessageDialog" wants you to.
*/
object[][] buttons = new object[][]
{
button_one,
button_two
};
// Displays a popup message with multiple buttons
ShowMessage("Title", "Content here", buttons);
/* Displays a popup message without multiple buttons.
* The last argument of the ShowMessage function is optional.
* because of the definition of the namespace "System.Runtime.InteropServices".
*/
ShowMessage("Title", "Content here");
// PS, I have a life, just trying to get points xD // BluDay
}
}
}
This way, you can display a message dialog with or without passing an object array with subarrays that contains of buttons. This method is extremely efficient. If you like this, make sure you fully understand it!

Show the new form after Progress Bar percentage completed c# project

I am working on a project using Visual Studio(c#). I want to create a startup form when i install my application with a progress bar. And after progress bar completed this form should be hide and a new form should be open. can u help me about this problem?
Edit:
I've just made a sample application trying to use exactly the code that you've specified. It worked fine besides just one tweak:
Form1().Show(); should be new Form1().Show();
The only way this code does not execute is if you forgot to set timer1 to enabled state in design view which causes the code to never fire up.
Are you sure the code is firing up? have you done a break-point on this piece of code?
On a sidenote: timer1 is not on a separate thread so you don't need to use Invoke (you can see if you actually need it by looking InvokeRequired property of a control)
Suggested improvement: if you are not going to use Form2 again and judging from your code, it is likely you won't; perhaps you should call Close() on Form2 instead of Hide() and release the resources. I've had times when my application kept running in background because I hid the form but never closed it and application was on "exit when last window closes" which never happened.
So to be sure, here is the final code that does work on my machine:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
//enable timer1 here or in designer
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
//disable timer1 first thing, otherwise it can end up ticking
//multiple times before you've had a chance to disable it
//if the timespan is really short
timer1.Enabled = false;
int d;
for (d = 0; d <= 100; d++)
progressBar1.Value = d;
Hide();
//create a new Form1 and then show it
new Form1().Show();
}
}
}
Create your form and add your progress bar
Set up event handlers on the parts of the form that should effect the progress bar
Update the progree bar to reflect the amount of work that is done
When the form is complete close it
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
int d;
for (d = 0; d <= 100; d++)
progressBar1.Value = d;
this.Hide();
Form1().Show();
timer1.Enabled = false;
}
}
}

winforms Label flickering

I have a problem with the Label control that is terribly flickering.
Below is some code to reproduce the problem.
How to solve this?
UPDATE: The solution for the previous case (a Form contains a Label directly) was to make the form.DoubleBuffered = true. But this is not a generic solution. For example, what should I do in the case of label inside a SplitContainer? this is my real case.
UPDATED CODE:
DoubleBufferedLabel.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace FlickerLabelTest
{
public class DoubleBufferedLabel : Label
{
public DoubleBufferedLabel()
{
DoubleBuffered = true;
}
}
}
DoubleBufferedSplitContainer.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace FlickerLabelTest
{
public class DoubleBufferedSplitContainer : SplitContainer
{
public DoubleBufferedSplitContainer()
{
DoubleBuffered = true;
}
}
}
Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace FlickerLabelTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text += "0";
}
}
}
Form1.Designer.cs:
namespace FlickerLabelTest
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.label1 = new FlickerLabelTest.DoubleBufferedLabel();
this.splitContainer1 = new DoubleBufferedSplitContainer();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.SuspendLayout();
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 1;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// label1
//
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(186, 262);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.Location = new System.Drawing.Point(0, 0);
this.splitContainer1.Name = "splitContainer1";
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.label1);
this.splitContainer1.Size = new System.Drawing.Size(284, 262);
this.splitContainer1.SplitterDistance = 94;
this.splitContainer1.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.splitContainer1);
this.DoubleBuffered = true;
this.Name = "Form1";
this.Text = "Form1";
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer timer1;
private DoubleBufferedLabel label1;
private DoubleBufferedSplitContainer splitContainer1;
}
}
Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace FlickerLabelTest
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
The problem is with the docking. If you change the Label.Dock from Fill to None, manually set the size of the label to fill the split panel and then anchor it on all sides, it won't flicker.
If you want to see the cause of the flicker, while Dock is still set to Fill, override OnResize in your DoubleBufferedLabel class, start the application, and while it is running set a breakpoint in OnResize. Add a watch for the Size and you'll see it flipping between its design time and runtime sizes.
I tried using a regular SplitContainer and Label in your example, set DoubleBuffer to False on the form, and it did not flicker if I left Dock set to None on the Label.
I think you're looking for this: http://msdn.microsoft.com/en-us/library/3t7htc9c.aspx
example:
class Form1 : Form
{
public Form1() {
this.DoubleBuffered = true;
}
}
Paste this into your form code to help the Dock layout calculations:
protected override void OnLoad(EventArgs e) {
label1.Size = this.ClientSize;
base.OnLoad(e);
}
Not really an answer, but why would you want to update your label each millisecond?
If you meant 1 second, you'd have to set your interval to 1000.
You can solve this by giving the form time to redraw itself and using a larger interval.
Update: turned out, setting DoubleBuffered to true solves the problem. Thanks for csharptest.net for pointing this out and DxCK for correcting me.
Activating Double Buffering on the form will fix the problem. But that is actually an expensive solution. If you just add the following to the form:
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
the flicker will be over too.
The default behavior of the Windows OS it to first let all windows paint their background, and later, let them do actual painting. This is from the old days, when painting letters actually took considerable amount of time. This flag tells it to fold the background paint and the regular paint (for the same window) immediately after each other.
Real Double buffering can be reserved for the cases where you actually do painting yourself (when you override OnPaint).
Stop setting timers to 1ms. No seriously, what you see here is that the Label tries to keep up with it's changes, but fails to do so because they're to frequent. So possible solutions are:
Choose a way to change the Label less often
Activate Double-Buffering on the Form
Why not run your label update function via an asynchronous delegate? Or use System.Threading namespace for a different flavor.
Also, as people before me mentioned, it would be useful if you set the DoubleBuffer property on your form to true (it's no silver bullet though).

Windows Forms Opacity After Shown- C#

I am tryig to fade-in a windows form using c# but it doesnt seem to work after I have shown the form. Is it possible to change the forms opacity after Ive shown it?
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;
namespace ToolStrip
{
public partial class Form1 : Form
{
Form ToolForm = new ToolForm();
Form PropForm = new PropertyGrid();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ToolForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
ToolForm.Owner = this;
ToolForm.Show();
ToolForm.Location = new Point(50, 50);
}
private void button2_Click(object sender, EventArgs e)
{
PropForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
PropForm.Owner = this;
PropForm.Show();
PropForm.Location = new Point(50, 50);
System.Timers.Timer aTimer = new System.Timers.Timer(10000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
PropForm.Opacity = PropForm.Opacity - 0.25;
Console.WriteLine(PropForm.Opacity);
}
}
}
because you r using System.Timers.Timer which is a multithread timer, in it's OnTimedEvent() it calls control created by another thread, which cause exception.
If you use System.Windows.Forms.Timer, it will work. i tested.
Using your code (and creating the other necessary Form classes), I get a cross-threading exception the first time the timer fires and the event handler is called, as Benny suggests.
Making changes to your code to check InvokeRequired in the timer event handler, and use Invoke if necessary to change PropForm.Opacity, results in the opacity changing after the form is shown, as required.
Note that you probably want to start with an Opacity of 0, and increase it gradually - otherwise your form will start off completely solid and gradually fade out
I will mention in passing that Opacity will have no effect on some versions of Windows, though you say you have Opacity effects working elsewhere, so it shouldn't be that in this case.
Ive gotten it to work without timers:
int Loop = 0;
for (Loop = 100; Loop >= 5; Loop -= 10)
{
this.PropForm.Opacity = Loop / 95.0;
this.PropForm .Refresh();
System.Threading.Thread.Sleep(100);
}
but i cant seem to change this example to fade-in instead of out.

Categories