Show always active form in winforms - c#

I need to show form that will be always on a top level.
I use TopMost and TopLevel flags and call Activate method after Show.
But another window might steal Activate flag.
How I can fix it so that after creating a window, other windows cannot become active until this window is closed?
upd: it work only if execute app from output folder and don't work if run app with debug from IDE.

The following code will open a form (TestForm) when the program is started. TestForm contains a button, that when clicked, will create a new form (a new instance of TestForm in the code below, but it could be a different form, if desired)--which won't be visible until the current form is closed. When the current form is closed, the new form will become visible and the original form will be disposed.
Try the following to see if it gives you the desired result:
Create a new class (TestFormEventArgs)
In Visual Studio menu, click Project
Select Add New Item
Select Class (Name: TestFormEventArgs.cs)
Click Add
TestFormEventArgs.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Activate2ndFormWhen1stFormCloses
{
public delegate void TestFormNewFormRequestedEventHandler(object sender, TestFormEventArgs e);
public class TestFormEventArgs : System.EventArgs
{
public int CurrentFormNumber { get; private set; } = 1;
public TestForm Frm { get; private set; } = null;
public TestFormEventArgs(TestForm frm, int currentFormNumber)
{
this.Frm = frm;
this.CurrentFormNumber = currentFormNumber;
}
}
}
Create a new Form (TestForm)
In Visual Studio menu, click Project
Select Add New Item
Select Form (Windows Forms) (Name: TestForm.cs)
Click Add
Add button to TestForm (btnOpenNewForm)
In Visual Studio menu, click View
Select Toolbox
Click Button
Drag mouse over the top of TestForm, and click the mouse to add the button to TestForm
In Visual Studio menu, click View
Select Properties Window
Click the button on the form
In the Properties Window, set the following properties: (Name): btnOpenNewForm; Text: Open New Form
On TestForm, double-click btnOpenNewForm which will create btnOpenNewForm_Click event handler.
Double-click TestForm to go to the code. Modify the code for TestForm.cs:
TestForm.cs
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 Activate2ndFormWhen1stFormCloses
{
public partial class TestForm : Form
{
public event TestFormNewFormRequestedEventHandler NewFormRequested;
private int _currentFormNumber = 1;
TestForm _frmOther = null;
public TestForm()
{
InitializeComponent();
//set value
this.Text = "TestForm 1";
}
public TestForm(string frmText, int currentFormNumber)
{
InitializeComponent();
//set value
this.Text = frmText;
this._currentFormNumber = currentFormNumber;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void SendUpdates(TestForm frm, int currentFormNumber)
{
//check if there are subscribers
if (NewFormRequested != null)
{
//create a new instance of TestFormEventArgs
TestFormEventArgs valueArgs = new TestFormEventArgs(frm, currentFormNumber);
//raise event
NewFormRequested(this, valueArgs);
}//if
}
private void btnOpenNewForm_Click(object sender, EventArgs e)
{
string frmText = String.Format("TestForm {0}", _currentFormNumber + 1);
//create new instance
_frmOther = new TestForm(frmText, _currentFormNumber + 1);
//set properties
_frmOther.StartPosition = FormStartPosition.CenterScreen;
_frmOther.Visible = false;
SendUpdates(_frmOther, _currentFormNumber);
}
}
}
Change Program.cs code to the following:
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
namespace Activate2ndFormWhen1stFormCloses
{
static class Program
{
static TestForm _currentFrm = null;
static Queue<TestForm> _frmQ = new Queue<TestForm>();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//place form in Queue
_frmQ.Enqueue(new TestForm());
while(_frmQ.Count > 0)
{
//dequeue
_currentFrm = _frmQ.Dequeue();
//subscribe to events
_currentFrm.FormClosed += CurrentFrm_FormClosed;
_currentFrm.NewFormRequested += CurrentFrm_NewFormRequested;
Application.Run(_currentFrm);
}
}
private static void CurrentFrm_NewFormRequested(object sender, TestFormEventArgs e)
{
Debug.WriteLine("CurrentFrm_NewFormRequested: " + e.Frm.Text);
//add form to Queue
_frmQ.Enqueue(e.Frm);
}
private static void CurrentFrm_FormClosed(object sender, FormClosedEventArgs e)
{
TestForm frm = (TestForm)sender;
Debug.WriteLine("CurrentFrm_FormClosed: " + frm.Text);
try
{
//unsubscribe from events
_currentFrm.FormClosed -= CurrentFrm_FormClosed;
_currentFrm.NewFormRequested -= CurrentFrm_NewFormRequested;
_currentFrm.Dispose();
_currentFrm = null;
}
catch(Exception ex)
{
Debug.WriteLine("Error: " + ex.Message);
}
}
}
}

Try ShowDialog() instead of Show() method.
ShowDialog() will make the other form that is open Disabled and the current form is the only one that is Enabled.

Related

c# unable to interact with listbox from another form

I have the following form with a method called setIndex
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 ProjectName
{
public partial class SettingsWindow : Form
{
internal readonly static SettingsWindow Instance = new SettingsWindow { Visible = false };
public SettingsWindow()
{
InitializeComponent();
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string defaultsearch = listBox1.GetItemText(listBox1.SelectedItem);
Core.RegistryHelper.SaveSetting("Config", "ds", defaultsearch);
if (defaultsearch == "aaa") {
Core.LandingUrlOrig = Core.DomainName + "/defaulturl1.php";
} else {
Core.LandingUrlOrig = Core.DomainName + "/defaulturl2.php";
}
}
public static void setIndex(int i)
{
listBox1.SelectedIndex = i;
}
On another form called MainWindow during its initialization I call:
public MainWindow()
{
SettingsWindow.setIndex(0);
}
The error I get is:
An object reference is required for the non-static field, method, or property 'SettingsWindow.listBox1'
Initially the listbox method wasn't static and thus invisible from MainWindow. But now, listbox appears to not exist, even if the form has been instantiated. How do I solve this? I'm just learning C#.
Thank you in advance
because the function setIndex is static you need to use the Instance property:
public static void setIndex(int i)
{
Instance.listBox1.SelectedIndex = i;
}
or don't make that function static and then use instance in the mainwindow function:
public void setIndex(int i)
{
listBox1.SelectedIndex = i;
}
public MainWindow()
{
SettingsWindow.Instance.setIndex(0);
}

Button classes that I've written with C# won't show up in Windows Form when running

Just started learning Visual Studio and I'm trying to make a soundboard in Windows Forms.
ButtonMaker(); is the function I use to make a button for each soundfile in my directory so I don't have to make 70 different buttons for every sound, but when I run the program nothing shows up in the forms window. Anybody know why? I've tried calling the function in Main() and in the initial Form1 class but nothing happens in either. Forms class file here:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace MySoundBoard
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
///Tried running it here
}
private void Form1_Load(object sender, EventArgs e)
{
///Tried running it here
}
private void ButtonMaker()
{
string[] files = Soundfiles.GetFile();
foreach (var item in files)
{
string btnName = item.ToUpper();
Button btNname = new Button();
btNname.Text = item;
int x = 40;
int y = 40;
btNname.Location = new Point(x, y);
x = x + 50;
if (x>900)
{
x = 40;
y = y + 30;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
}
}
}
Here is the SoundFiles class:
using System.IO;
using System;
using System.Text;
using System.Diagnostics;
using WMPLib;
namespace MySoundBoard
{
class Soundfiles {
WMPLib.WindowsMediaPlayer Player;
static public string[] GetFile() {
string txtPath = #"C:\Documents\path\to\sound effects";
string[] files =
Directory.GetFiles(txtPath, "*ProfileHandler.cs", SearchOption.TopDirectoryOnly);
return files;
}
public void PlayFile(String url)
{
Player = new WMPLib.WindowsMediaPlayer();
Player.URL = url;
Player.controls.play();
}
}
}
And the main project file(not that worked with yet):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MySoundBoard
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
///Tried running it here
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
As said, I'm very new to this language and any help would be appriciated!
You create the buttons but never add them to the form. Just add
this.Controls.Add(btNname);
The next thing is, that your buttons will not do something. You'll need to add an event handler as well.
btNname.Click += ...;
In order to know which button plays which sound, you need to find a way to have that association. A hacky approach is
btNname.Tag = item;
and then evaluate Tag later

Cannot enter text from class to textbox in form

Cannot enter text from class to textbox in form.
We set a keypress event in the MyTreeView class.
The text box cannot contain characters.
What should I do?
*set of textBox1.
*Change Modifiers for textBox1 properties from private to public
*Change keypress event from private to public
*(It didn't work well, so I keep it private now.)
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.Diagnostics;
namespace treeview
{
public partial class Form1 : System.Windows.Forms.Form
{
MyTreeView m_tree_view = new MyTreeView();
public Form1()
{
try
{
InitializeComponent();
System.Windows.Forms.TreeNode[] tree1 = new System.Windows.Forms.TreeNode[2];
m_tree_view.Location = new System.Drawing.Point(0, 0);
m_tree_view.Size = ClientSize;
m_tree_view.AllowDrop = true;
tree1[0] = new System.Windows.Forms.TreeNode("TreeNode1");
tree1[1] = new System.Windows.Forms.TreeNode("TreeNode2");
m_tree_view.Nodes.Add("Node1");
Controls.Add(m_tree_view);
}
catch
{
}
}
//This is the code I added.
private void Form1_Load(object sender, EventArgs e)
{
}
}
public class MyTreeView : System.Windows.Forms.TreeView
{
public MyTreeView()
{
try
{
//This is the code I added.
KeyPress += MyTreeView_KeyPress;
}
catch
{
}
}
//This is the code I added.
private void MyTreeView_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
Console.WriteLine("key_press_ok");
//error code↓
//textBox1.Text = "sample";
}
}
}
If you want just to click an button and then print some text i don't understand why you are making another class.
Will be good to make your code efficient and not complicated.
In the main class
private void SendText_Click(object sender, EventArgs e)
{
textBox1.Text = "hi";
}
But if you want to make it complicated and make a class you shuld return i variable and send it to the other class the you can use it.
Learn how to use Public and private first and then use them.
You shuld have a public class which send data and the private to recive and process.
add (Exception ex) to your try catch.
so do:
try
{
// your code
}
catch (Exception ex)
{
MessageBox.Show(ex, "Error in (add where the error is)");
Console.WriteLine(ex);
}
So you will get a detailed Exception Message, maybe it helps you or maybe you will post it here, so we can see what the problem is.
And because you have System.Windows.Forms in your Using Directive
using System.Windows.Forms;
so
System.Windows.Forms.TreeNode[] tree1 = new System.Windows.Forms.TreeNode[2];
is redundant and can be shortened to:
TreeNode[] tree1 = new TreeNode[2];

How to dynamically add menu item in Systray app using C#

I would like to dynamically add a menu item to a systray app. I already have an "Exit" and "Add more" menu. I would like to add more menus at run-time when I click on Add more.
For example, when I clicked on Add more, it automatically add a new menuItem to the tray App.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
NotifyIcon notify = new NotifyIcon();
notify.ContextMenuStrip = MainContextMenu();
notify.Icon = new Icon("Led.ico");
notify.Visible = true;
Application.Run();
}
private static ContextMenuStrip MainContextMenu()
{
ContextMenuStrip ConextMenuApp = new ContextMenuStrip();
ConextMenuApp.Items.Add("Add More", null, new EventHandler(AddMoreMenus));
ConextMenuApp.Items.Add("-");
ConextMenuApp.Items.Add("Exit", null, new EventHandler(Exit_Click));
return ConextMenuApp;
}
private static ContextMenuStrip AddMoreMenus(Object sender, EventArgs e)
{
ContextMenuStrip AddNewMenu = new ContextMenuStrip();
AddNewMenu.Items.Add("Menu One Addedd");
return AddNewMenu;
}
private static void Exit_Click(Object sender, EventArgs e)
{
Application.Exit();
}
}
}
There are many ways you can do this, however the simplest way is just hold a Reference to the MenuStrip or MenuStrip Item and pass it around.
Though in all honesty, just choose your poison:
Make a DI Service that holds the Reference
Make it Static
Pass it in as a Reference to the classes who want to manipulate it
Use Decouple Message or an Event Aggregator or some other pub/sub architecture

Passing txtBox values between forms

I have always had trouble with this issue, i think i need to learn how it works, i have FormMain (my main form) and a second form (FormAddUrls) when i open form2 (FormAddUrls) i want to pass the multitextbox value back to the main form (FormMain)
I know in VB it's as simple as saying: FormMain.txtBoxUrls.Text = finalOutput; but not as easy in C#.
(form1) - FormMain
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using WraithProjectCreator;
using IronPdf;
using System.Text;
namespace GSAProjectCreator
{
public partial class FormMain : Form
{
private IniParser m_Parser = null;
public FormMain()
{
InitializeComponent();
}
private void btnShowUrlsForm_Click(object sender, EventArgs e)
{
FormAddUrls fau = new FormAddUrls();
fau.Show();
}
}
}
(form2) - FormAddUrls
using GSAProjectCreator;
using System;
using System.Text;
using System.Windows.Forms;
namespace WraithProjectCreator
{
public partial class FormAddUrls : Form
{
public FormAddUrls()
{
InitializeComponent();
}
private void btnAddUrls_Click(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
builder.Append("{");
foreach (string line in txtBoxURLsMass.Lines)
{
//Helpers.returnMessage(line);
builder.Append(line + "|");
}
builder.Append("}");
string finalOutput = "";
if (builder.ToString().Contains("|}")) {
finalOutput = builder.ToString().Replace("|}", "}");
}
//FormMain.txtBoxUrls.Text = finalOutput;
this.Close();
}
}
}
I have ommited a lot of form1's code to leave the basic structure, i'm trying to pass back finalOutput from form2 to form1 (the txtBoxUrls.Text) text box, any help would be appreciated.
It depends on how you want to use the main form - you could have a static property which you could set (which would update the text for all main form instances).
If you only have one main form, and have a reference to it when you create the FormAddUrls object then you should just change the constructor to accept a MainForm (or as generic a type as possible), store the reference as a field and update the property on it when the button is clicked:
public partial class FormAddUrls : Form
{
private readonly Form _parentForm;
public FormAddUrls(MainForm parent)
{
_parentForm = parent;
InitializeComponent();
}
private void btnAddUrls_Click(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
builder.Append("{");
foreach (string line in txtBoxURLsMass.Lines)
{
//Helpers.returnMessage(line);
builder.Append(line + "|");
}
builder.Append("}");
string finalOutput = "";
if (builder.ToString().Contains("|}")) {
finalOutput = builder.ToString().Replace("|}", "}");
}
if(_parentForm != null)
_parentForm.txtBoxUrls.Text = finalOutput;
this.Close();
}
}

Categories