How to change a PictureBox image from another Form - c#

I want to open form2 while form1 loads. Also, I want to change the Image of a PictureBox in form2 when an action is triggered in form1.
To open form2 while form1 loads I used this code:
private void MONITOR3_Load(object sender, EventArgs e)
{
MONITOR4 mo4 = new MONITOR4(this);
mo4.Show();
}
To change the Image of the PictureBox in form2 I used this code, which is must to be run after a condition is met:
if (textBox1.Text == #"QUEBEC - ALPHA - TANGO - ALPHA - ROMEO - ")
{
MONITOR4 mo4 = new MONITOR4(this);
mo4.pictureBox1.Image = Image.FromFile("D:/QResources/images/HIA.jpg");
}

There are two problems with your current code:
You don't have to create a new Form instance each time you need to set some of its properties: store a reference to this Form and use this reference to call public properties or methods of the Form.
You are trying to directly access a child Control's properties of another Form. Event though you can define a child Control public, you shouldn't and it's not necessary. A Form is a class like any other in this aspect: create a public method on the Form that provides means to modify a private property, without directly exposing a Control's property to direct access.
It's simple, safer and more portable: if a Control needs to be modified (the name is changed, the type of Control is changed etc.), you don't need to go on a hunt to find where the old name/properties have been used in other classes.
The public method will be the same and it's the only responsible to reference the current names, properties of the affected Control. A single place where the code, eventually, needs to be modified.
You could also use a public event or implement INotifyPropertyChanged to notify the subscribers that some properties have changed.
Here, I'm creating a reference to Monitor4 in the Monitor3 Form:
Monitor4 mo4 = null;
This reference will be use to call a public method (UpdatePictureBox) of Monitor4.
Monitor3 Form:
(I'm using the TextChanged event of a TextBox to select the Image to show in the Monitor4 PictureBox. Of course, it could be the Validate event or anything else that agrees with your design)
public partial class Monitor3 : Form
{
Monitor4 mo4 = null;
private void Monitor3_Load(object sender, EventArgs e)
{
mo4 = new Monitor4();
//Show Monitor4 on the right side of this Form
mo4.Location = new Point(this.Right + 10, this.Top);
mo4.Show(this);
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
string newText = textBox1.Text;
switch (newText) {
case "[Some text 1]":
mo4.UpdatePictureBox(#"[Images1 Path]");
break;
case "QUEBEC - ALPHA - TANGO - ALPHA - ROMEO - ":
mo4.UpdatePictureBox(#"[Images2 Path]");
break;
case "[Some text 3]":
mo4.UpdatePictureBox(#"[Images3 Path]");
break;
}
}
}
Monitor4 Form:
public partial class Monitor4 : Form
{
public void UpdatePictureBox(string imagePath)
{
if (File.Exists(imagePath)) {
pictureBox1.Image?.Dispose();
pictureBox1.Image = Image.FromFile(imagePath, true);
}
}
}
Sample result:

Related

Pass an integer from one form to another to do some work

My question is about dealing with multiple forms in C# Windows form application. I am developing a code for playing a movie and moving it frame by frame with buttons. I already have the code for moving the movie frame by frame with ctlcontrols in Windows Media Player.
The thing that I'm having an issue with is that I want to have a main form and a movie form, and when I click the button in the main form, I want to send a number to the other form and if the number was 2, I want the movie to go frame by frame in the movie form. And I want to do it without opening a new form every time I click the button. I have made a function in my second form and I called it in the button in the main form. It is expected to work but it doesn't.
The code for the button in the main form is:
private void button1_Click(object sender, EventArgs e)
{
value = txtSendNum.Text; // get the value from the textox and
// assign it to string variable
MovieForm movieform = new MovieForm(); //create an object for MovieForm
movieform.ConnectForms(value);
}
The code for the function(ConnectForms function) in the second form is:
public void ConnectForms(string value)
{
val = Convert.ToInt32(value);
if (val == 2)
{
axWindowsMediaPlayer1.Ctlcontrols.play();
axWindowsMediaPlayer1.Ctlcontrols.currentPosition += 0.5;
axWindowsMediaPlayer1.Ctlcontrols.stop();
}
}
You are creating a new MovieForm every time the user clicks the button, this is wrong. You need a reference to the MovieForm that was previously open.
This is the difference between the meaning of Object and Class. You need a reference to the object not a new object from the same class.
A simple way to make it work is like the following code:
MovieForm movieform = null;
private void button1_Click(object sender, EventArgs e)
{
value = txtSendNum.Text;
if(movieform == null || movieform.IsDisposed)
{
movieform = new MovieForm(); //create an object for MovieForm
movieform.Show();
movieform.ConnectForms(value);
}
else
{
movieform.ConnectForms(value);
movieform.Focus();
}
}
You must have a reference the the other form. Instead of declaring movieform as a local variable, declare it as a class level variable (i.e., a field)
private MovieForm _movieform = new MovieForm();
private void button1_Click(object sender, EventArgs e)
{
value = txtSendNum.Text; //get the value from the textox and assign it to string variable
_movieform.ConnectForms(value);
_movieform.Show();
}
A local variable, i.e., a variable declared in a method has a lifetime limited to one method call (I'm not talking about special cases like iterators and closures).
A class field has the same lifetime as the object (here the Form).
Instead of creating a method on each form that receives a value or passing the value as parameter on the constructor of each form, or creating a new property to set the value to search for it later you should use the Tag property of the Control that is already created for that. Here you is how it is used
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.tag?view=netframework-4.7.2
private void buttonNewCustomer_Click(object sender, EventArgs e)
{
/* Create a new customer form and assign a new
* Customer object to the Tag property. */
CustomerForm customerForm = new CustomerForm();
customerForm.Tag = new Customer();
customerForm.Show();
}

How to avoid the MaskedTextBox PromptChar being removed, when its container modal Form is shown?

Using VS 2015 and C#...
I have this simple modal Form with just a MaskedTextBox control on it.
Each time after the first that ModalForm is shown with .ShowDialog(), the PromptChar in the control is gone.
To reproduce this issue:
public ModalForm()
{
InitializeComponent();
maskedTextBox1.Mask = "00/00/0000"; // happens with any
maskedTextBox1.TextMaskFormat = MaskFormat.IncludeLiterals;
}
Code for main Form:
public partial class Form1 : Form
{
private ModalForm modalForm = new ModalForm();
private void button1_Click(object sender, EventArgs e)
{
modalForm.ShowDialog();
}
}
The control's prompt appears again when its content changes, but at first view isn't present.
Setting the TextMaskFormat property to IncludePromptAndLiterals could be a solution, but then, .Text has to be cleaned up.
Is there another way to handle this?. Has become necessary for me, that all MaskedTextBox controls must always show its default prompt.
Try this on Form's Shown event,
private void ModalForm_Shown(object sender, EventArgs e){
if (!maskedTextBox1.MaskCompleted) // if there is missing parts it will return false, every false means prompts need in control
{
string tempText = maskedTextBox1.MaskedTextProvider.ToDisplayString(); // get the last value with prompts
maskedTextBox1.Text = "";
maskedTextBox1.Text = tempText; // then set the last value.
}
}
Hope helps,

Reloading the form instead of making a new one / accessing textbox outside of form

I am having a problem controlling a textbox. I need to change a value from outside of Form1.cs where the textbox is located for this I have found this snippet.
public void UpdateText(string newValue)
{
torrent_name0.Text = newValue;
}
this allows me in theory to control the textbox outside of Form1.cs, but here comes the problem, every time I want to access it I create a new instance of Form1 instead of using the old one and refreshing it.
Form1 frm = new Form1();
frm.UpdateText("aaaaaaaaaaaa");
frm.Show();
am I missing something? is there a better way to do this? I have tried multiple ways to update the new form but got nowhere.
Bokker,
You will have to have a reference to the singular form1 to which all things refer.
If this is a child form, then as Aybe commented, create a public member of your mainform and name it something.
Public Form myForm1;
You probably have some Event by which you would like Form1 be launched...
A Button click, menu item, toolbar item, etc. In that event you will have to check if the form exists and create if required.
private SomeEvent() {
if (myForm1 == null)
{
myForm1 = new Form1();
myForm1.Show(this);
}
myForm1.UpdateText("some text");
}
Alternatively, you could create the form in the Form Load event, just so long as you create the form prior to attempting the myForm1.UpdateText()
If you follow this paradigm, you are creating myForm1 as part of the main form, best practice says you should also dispose of the form in your main form Closing Event.
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (myForm1 != null)
{
myForm1.Close();
myForm1.Dispose();
}
}
This is all off the top of my head, so it might not be perfect.
In that case you can pass the instance of form in the method as argument and make the changes like
public void UpdateText(string newValue, Form1 frm)
{
frm.torrent_name0.Text = newValue;
}

Winforms Control

I have a button which I use all the time as a little pick button next to a combobox. When I click the button I open a larger full list. This side of things work well and I do not have a problem with this..
My problem lies when someone said to me can you change that ugly icon you picked to my nice icon.
I went crap, I have hundreds of these buttons on many forms. So I thought I will create a custom control called PickButton (which is a standard button and heap of default proeprties set) and drop these on the form everywhere instead. In the code of the PickButton custom control I set some properties and the image to the customers nice icon.
So I drop the PickButton from my toolbox onto the form, so far things are looking pretty good and I am feeling a bit clever. Now I think to myself I will change back to my nice icon not the crappy one the customer picked and change the code in the PickButton custom control. But I cannot get rid of that customers icon, because the code when the PickButton run happens before the code in the designer file which has the customers icon.
So my aim was to have a PickButton control and be able to change the icon and other properties in one place and all the properties would be set when an instance of the control is created and displayed on the form.
Was I not so clever and went about achieving the task the wrong way???
This is my PickButton custom control class
public class PickButton : Button
{
public PickButton()
{
InitialiseButton();
}
internal void InitialiseButton()
{
this.ImageAlign = ContentAlignment.MiddleCenter;
this.Image = WindowsFormsApplication1.Properties.Resources.Cancel.ToBitmap();
this.Size = new Size( 28, 28 );
this.Dock = DockStyle.Fill;
this.Margin = new Padding( 0, 2, 2, 0 );
this.Text = string.Empty;
}
}
Now I drop one onto my form and the code in the designer is as follows
//
// pickButton1
//
this.pickButton1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pickButton1.Image = ((System.Drawing.Image)(resources.GetObject("pickButton1.Image")));
this.pickButton1.Location = new System.Drawing.Point(0, 0);
this.pickButton1.Margin = new System.Windows.Forms.Padding(0, 2, 2, 0);
this.pickButton1.Name = "pickButton1";
this.pickButton1.Size = new System.Drawing.Size(284, 262);
this.pickButton1.TabIndex = 0;
this.pickButton1.Text = "pickButton1";
this.pickButton1.UseVisualStyleBackColor = true;
Now I want to change the image so I change my PickButton code to use a different icon
this.Image = WindowsFormsApplication1.Properties.Resources.Browse.ToBitmap();
Run the application andd the first icon is still the one being displayed because of this line of code in the designer file
this.pickButton1.Image = ((System.Drawing.Image)(resources.GetObject("pickButton1.Image")));
The concept of setting all the properties in one place was a good idea, it just wasn't implemented quite right. I would make this class inherit from UserControl instead of from Button. By making it a UserControl, you can use the designer to set all the properties you want, like the default Image for the button. Set that in the designer, then just drag and drop your UserControl from the toolbox onto your forms. If you are only using your "PickButton" control with comboboxes, I would put the combobox on the UserControl as well. If you ever want to change your button image in the future (or any other property for that matter), you will be able to change it in ctlPickButton and that will propogate the changes to all the instances used throughout your project(s).
ctlPickButton:
public partial class ctlPickButton : UserControl
{
public event EventHandler pickButtonClicked;
public ctlPickButton()
{
InitializeComponent();
}
//Allows buttons image to be set in code if necessary
public Image Image
{
get
{
return button1.Image;
}
set
{
if (Image != null)
{
button1.Image = value;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
if (pickButtonClicked != null)
{
pickButtonClicked(sender, e);
}
}
}
Demo Form:
public Form1()
{
InitializeComponent();
ctlPickButton1.pickButtonClicked += new EventHandler(ctlPickButton1_pickButtonClicked);
ctlPickButton2.pickButtonClicked += new EventHandler(ctlPickButton2_pickButtonClicked);
}
void ctlPickButton2_pickButtonClicked(object sender, EventArgs e)
{
if (comboBox2.SelectedItem != null)
{
MessageBox.Show(comboBox2.SelectedItem.ToString());
}
}
void ctlPickButton1_pickButtonClicked(object sender, EventArgs e)
{
if (comboBox1.SelectedItem != null)
{
MessageBox.Show(comboBox1.SelectedItem.ToString());
}
}
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.Add("French");
comboBox1.Items.Add("Spanish");
comboBox1.Items.Add("English");
comboBox1.Items.Add("German");
comboBox2.Items.Add("Pizza");
comboBox2.Items.Add("Hamburger");
comboBox2.Items.Add("Potato");
comboBox2.Items.Add("Chicken");
//Shows how the default image set in the designer can be overwritten for a
//specific instance using the "Image" property
ctlPickButton2.Image = Testbed.Properties.Resources.searchIcon2;
}
}
Image of ctlPickButton in designer
I think I've found a simple, clean solution:
In the CustomButton class (which inherits from System.Windows.Forms.Button), override the Refresh() method, and set the image of the button to the one you want to see:
public class CustomButton : Button
{
public override void Refresh()
{
Image = MyResources.HappyFace;
}
}
In the form that will hold an instance of your CustomButton, simply call customButton.Refresh() in the constructor, after InitializeComponent():
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
customButton.Refresh();
}
}
I've put a demo application up on Github.

How to access controls on an inherited form?

I'm using the DockPanel Suite in my winforms app. The DockContent class is derived from System.Windows.Forms.Form class and my two forms, dockRounds and dockToolbox, inherit from the DockContent class.
This is the first time I've done this and this is probably a stupid question, but in runtime, how do I access the controls of the dockRounds and dockToolbox forms?
Here is how I load the two forms when the app first runs:
public partial class frmMainNew : Form
clsMWDockPanel mapPanel;
dockToolbox dockT = new dockToolbox();
dockRounds dockR = new dockRounds();
public frmMainNew()
{
InitializeComponent();
dockPanel = new DockPanel();
SuspendLayout();
dockPanel.Parent = panelMain;
dockPanel.Dock = DockStyle.Fill;
dockPanel.DefaultFloatWindowSize = new Size(108, 528);
dockPanel.BringToFront();
dockPanel.BackColor = Color.Transparent;
dockPanel.DocumentStyle = DocumentStyle.DockingSdi;
ResumeLayout();
string error = "Errors:\r\n";
try
{
loadRounds();
loadToolbox();
}
catch (Exception)
{
error = error + "The Toolbox and/or Rounds menu could not be created\r\n";
}
}
public void loadToolbox()
{
dockT.CloseButton = false;
dockT.ShowHint = DockState.Float;
dockT.Text = "Toolbox";
dockT.BackColor = Color.WhiteSmoke;
dockT.Icon = this.Icon;
dockT.Show(dockPanel);
}
public void loadRounds()
{
if (mapPanel == null)
{
CreateMapPanel().Show(dockPanel, DockState.Document);
}
mapMain.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
//mapMain.BringToFront();
dockR.CloseButton = false;
dockR.ShowHint = DockState.DockRightAutoHide;
dockR.Text = "Rounds Menu";
dockR.BackColor = Color.WhiteSmoke;
dockR.Icon = this.Icon;
dockR.Show(dockPanel);
}
DockContent CreateMapPanel()
{
mapPanel = new clsMWDockPanel();
mapPanel.ShowHint = DockState.Document;
mapPanel.Controls.Add(mapMain);
return mapPanel;
}
Many thanks in advance
leddy
There are several strategies you can use to achieve communication/linkage between objects on different Forms. Note : My reply here is not going to address any issues specifically related to DockPanelSuite, and is not going to consider the difference between the "secondary" forms being "independent" (i.e., they are not "owned" by the MainForm) or being made child Forms of the MainForm. This is a conscious choice made on the basis of believing that what you are asking about is independent of those possible variations in implementation.
the simplest strategy (if tedious for a lot of controls) is to declare Public Properties in your secondary Forms that expose the controls you want to manipulate from your Main Form. For example, let's say Form2 has a button, and you want to handle its click event on your main form :
In Form2 define a property like :
public Button form2Button
{
get { return button1; }
}
Now in the Load event of your Main Form, assuming that's where an instance of Form2 is created, you can subscribe to the Click event of the Button on Form2 :
Form2 myForm2;
Form3 myForm3;
private void Form1_Load(object sender, EventArgs e)
{
myForm2 = new Form2();
myForm2.form2Button.Click += new EventHandler(form2Button_Click);
myForm3 = new Form3();
}
And you can easily imagine that in Form3 you have a TextBox that you have exposed with a Public Property in the same way you exposed the Button on Form2.
So you can implement the MainForm's event handler like this for the Button click on Form2 :
public void form2Button_Click(object sender, EventArgs e)
{
// do something here with the TextBox on Form3
// myForm3.theTextBox.Text =
}
... other strategies ...
in your secondary form, for example, a button press can raise a Public Event which the Main Form (or any other entity to which Form2 is exposed) could subscribe to and then dispatch the appropriate whatever to the appropriate target.
you can abstract message-passing in general at a higher level into a single (perhaps static) class where publishers send messages, and the messages are dispatched to registered listeners.
Finally, the discussion here may be of interest to you :
Using The Controls Of One Form Into Another
best,
Your classes, dockRounds and dockToolbox should expose any properties/events that you want to access. So if you want to hook up to a control's event, route it to a public event.
You can set the access modifier on a control to make it as accessible as you like. The default is "Private" which is why you can't access the controls from the main form.
In Visual Studio, on the Properties tab, there is a Modifiers property which sets the access modifier that is used in the generated designer file.
Set this to "Public" and you be able to access the control from the main form.
I've just used this when I inherited one form from another. By setting the modifier to "Protected" (or "Protected Internal") I was able to access the controls defined in the base class.
Have you tried accessing the Controls property?
var controls = dockRounds.Controls;

Categories

Resources