I have a custom TabPage class:
class CustomTabPage : TabPage
{
TextBox tbCode = new TextBox();
public CustomTabPage()
{
}
public CustomTabPage(string title)
{
tbCode.Multiline = true;
tbCode.Size = this.Size;
}
//Something like this...
private void OnThisControlSizeChanged()
{
tbCode.Size = this.Size;
}
}
What I need for this class is to raise the OnSizeChanged event of the TabPage control when I resize it from where I create the control. The reason for this is when I resize the TabPage control, I want to adapt the TextBox size accordingly so that they stay the same.
class CustomTabPage : TabPage
{
TextBox tbCode = new TextBox();
public CustomTabPage()
{
SizeChanged += CustomTabPage_SizeChanged;
}
void CustomTabPage_SizeChanged(object sender, EventArgs e)
{
OnThisControlSizeChanged();
}
public CustomTabPage(string title)
{
tbCode.Multiline = true;
tbCode.Size = this.Size;
}
private void OnThisControlSizeChanged()
{
tbCode.Size = this.Size;
}
}
this.OnSizeChanged(new EventArgs());
Related
So I have a form on a WinForms app.
On that form is a FlowLayoutPanel.
On the FlowLayout panel is a bunch of user controls each representing rows from a table from a database.
On each control is a button.
How do I have the form subscribe to a button click on one of the controls passing back that rows database info?
This is the control code:
public partial class ctrlLeague : UserControl
{
public League activeLeague = new League();
public event EventHandler<MyEventArgs> ViewLeagueClicked;
public ctrlLeague(League lg)
{
InitializeComponent();
lblLeagueName.Text = lg.leagueName;
activeLeague = lg;
}
private void btnViewLeague_Click(object sender, EventArgs e)
{
ViewLeagueClicked(this, new MyEventArgs(activeLeague));
}
public class MyEventArgs : EventArgs
{
public MyEventArgs(League activeLeague)
{
ActiveLeague = activeLeague;
}
public League ActiveLeague { get; }
}
}
if I put the following into the form constructor it tells me "
You can define your favorite event with delegate and call it wherever you want, here it is called inside btnView_Click.
This means that whenever btnView_Click called, your event is
actually called.
public partial class ctrlLeague : UserControl
{
public League activeLeague = new League();
public event EventViewLeagueClicked ViewLeagueClicked;
public delegate void EventViewLeagueClicked(object Sender);
public ctrlLeague(League lg)
{
InitializeComponent();
lblLeagueName.Text = lg.leagueName;
activeLeague = lg;
}
private void btnViewLeague_Click(object sender, EventArgs e)
{
if (ViewLeagueClicked != null)
ViewLeagueClicked(activeLeague);
}
}
now use
public Form1()
{
InitializeComponent();
League league = new League();
league.leagueName = "Seri A";
//
//These lines are best added in Form1.Designer.cs
//
ctrlLeague control = new ctrlLeague(league);
control.Location = new System.Drawing.Point(350, 50);
control.Name = "ctrlLeague";
control.Size = new System.Drawing.Size(150, 100);
control.ViewLeagueClicked += Control_ViewLeagueClicked;
this.Controls.Add(control);
}
private void Control_ViewLeagueClicked(object Sender)
{
League l = Sender as League;
MessageBox.Show(l.leagueName);
}
I have different Labels on my Form1 and want to change the text of a single Label using the same method.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Class1 change = new Class1();
change.ChangeLabelText();
}
public void ChangeLabel(string msg, Label label)
{
if (label.InvokeRequired)
label.Invoke(new MethodInvoker(delegate { label.Text = msg; }));
else
label.Text = msg;
}
}
how can i pass label1 or label2 as i need?
class Class1
{
public void ChangeLabelText()
{
Form1 frm1 = new Form1();
frm1.ChangeLabel("Surname", label2);
}
}
label2 is underlined of red: NOT EXIST IN THE ACTUAL CONTEST
I dont know what is the context in which you are trying to change the label... however I have a few observations seeing your sample code.
First of all, to your question, one of the approaches could be as follows,
private void button1_Click(object sender, EventArgs e)
{
Class1 change = new Class1(this);
change.ChangeLabelText();
}
public void ChangeLabel(string msg, Label label)
{
if (label.InvokeRequired)
label.Invoke(new MethodInvoker(delegate { label.Text = msg; }));
else
label.Text = msg;
}
// dont allow UI elements to be accessed directly from outide
public string Fullname
{
get
{
return label1.Text;
}
set
{
label1.Text = value;
}
}
// dont allow UI elements to be accessed directly from outide
public string Surname
{
get
{
return label2.Text;
}
set
{
label2.Text = value;
}
}
You see that object of Class1 gets reference to the Form1.
Inside Class1.ChangeLabelText you may do something like the following,
class Class1
{
Form1 _mainForm;
public Class1(Form1 form)
{
_mainForm = form;
}
public void ChangeLabelText()
{
//Form1 frm1 = new Form1();
//frm1.ChangeLabel("Surname", label2);
_mainForm.Surname = "Surname";
}
}
Observations after seeing your sample
It is a good practice not to expose/allow UI elements to be accessed by non-owner (Form1 is the owner in this case)
In button1_Click, you are already in a Form1 instance (object), however in ChangeLabelText, you are trying to create another instance of Form1.
Hope this helps you.
Another approach is to make Class1 raise an Event with the Name of the Label and the String to change it to. Your Form will receive the event, find the Label itself, and update the value. This way Class1 never needs a reference to Form1 or any of the Labels. It's still a bad design as you need to know the name of the Label, but this is the direction you went down anyways.
Here's what Class1 would look like:
public class Class1
{
public delegate void dlgChangeLabel(string lblName, string newValue);
public event dlgChangeLabel ChangeLabel;
public void ChangeLabelText()
{
if (ChangeLabel != null)
{
ChangeLabel("label2", "SurName");
}
}
}
Back in Form1, we need to subscribe to the ChangeLabel() event when we create our instance of Class1:
public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
Class1 change = new Class1();
change.ChangeLabel += Change_ChangeLabel;
change.ChangeLabelText();
}
private void Change_ChangeLabel(string lblName, string newValue)
{
// see if we have a Label with the desired name:
Control[] matches = this.Controls.Find(lblName, true);
if (matches.Length > 0 && matches[0] is Label)
{
Label lbl = (Label)matches[0];
ChangeLabel(newValue, lbl); // update it in a thread safe way
}
}
private void ChangeLabel(string msg, Label label)
{
if (label.InvokeRequired)
label.Invoke(new MethodInvoker(delegate { label.Text = msg; }));
else
label.Text = msg;
}
}
Alternate version showing the creation of Class1 and wiring up of its Event during Form Load() so it's not attached to the Button handler:
public partial class Form1 : Form
{
private Class1 change = new Class1();
private void Form1_Load(object sender, EventArgs e)
{
change.ChangeLabel += Change_ChangeLabel;
}
private void Change_ChangeLabel(string lblName, string newValue)
{
Control[] matches = this.Controls.Find(lblName, true);
if (matches.Length > 0 && matches[0] is Label)
{
Label lbl = (Label)matches[0];
ChangeLabel(newValue, lbl);
}
}
private void ChangeLabel(string msg, Label label)
{
if (label.InvokeRequired)
label.Invoke(new MethodInvoker(delegate { label.Text = msg; }));
else
label.Text = msg;
}
}
Now you simply need to raise that event somehow in Class1. Just make sure it has a subscriber (is not null) before you raise it:
// in Class1
private void Foo()
{
if (ChangeLabel != null)
{
ChangeLabel("label2", "SurName");
}
}
You need to pass label as a parameter in your method
class Class1
{
public void ChangeLabelText(Label lbl)
{
Form1 frm1 = new Form1();
frm1.ChangeLabel("Surname", lbl);
}
}
And in your button click -
change.ChangeLabelText(label2);
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Class1 change = new Class1();
change.ChangeLabelText(this);
}
public void ChangeLabel(string msg, Label label)
{
if (label.InvokeRequired)
label.Invoke(new MethodInvoker(delegate { label.Text = msg; }));
else
label.Text = msg;
}
}
class Class1
{
public void ChangeLabelText(System.Windows.Forms.Form form)
{
if(form != null)
{
var labelIdWhoseTextNeedsToChange = "label2"; // Or any dynamic logic to determine which label will have to be updated.
var labelControl = form.Controls.Find(labelIdWhoseTextNeedsToChange, false);
if(labelControl != null)
{
form.ChangeLabel("Surname", labelControl);
}
}
}
}
I want to implement a simple feature where user's can customize the Font of labels.
So I have FontEditor form with the following code:
public partial class FontEditor : Form
{
public Font myFont;
public FontEditor(Font myFont)
{
InitializeComponent();
this.myFont = myFont;
propertyGrid1.SelectedObject = this.myFont;
}
private void FontEditor_FormClosing(object sender, FormClosingEventArgs e)
{
DialogResult = DialogResult.OK;
}
}
I use it on a chart control like this:
using (FontEditor fe = new FontEditor(chart1.Titles[0].Font))
{
if (DialogResult.OK == fe.ShowDialog())
{
chart1.Titles[0].Font = fe.myFont;
}
}
When the font editor loads, i can see the following:
If I changed the Size from 18 to 10 and close the window, the SelectedObject (which is my font object from chart title) does not appear to be changing/updating:
Doesn't editing the property grid values should update the SelectedObject?
Okay, I realise the silly mistake. The edits you do on PropertyGrid are actually in propertyGrid1.SelectedObject.
This is how I fixed it:
FontEditor.cs
public partial class FontEditor : Form
{
public FontEditor(Font myFont)
{
InitializeComponent();
propertyGrid1.SelectedObject = myFont;
}
private void FontEditor_FormClosing(object sender, FormClosingEventArgs e)
{
DialogResult = DialogResult.OK;
}
public Font UpdatedFont
{
get { return propertyGrid1.SelectedObject as Font; }
}
}
Usage
using (FontEditor fe = new FontEditor(chart1.Titles[0].Font))
{
if (DialogResult.OK == fe.ShowDialog())
{
chart1.Titles[0].Font = fe.UpdatedFont;
}
}
This now works.
I'm creating a user control in C# but I can't figure out how to do the event stuff. I want to change the backcolor property of the panel on mouse hover but it's not working.
Code:
public partial class QuestionList : UserControl
{
public QuestionList()
{
InitializeComponent();
}
public struct QuestionListItem
{
public string Question { get; set; }
public string Answer { get; set; }
public QuestionListItem(string question, string answer)
{
Question = question;
Answer = answer;
}
}
public void Add(QuestionListItem questionlistItem)
{
Panel panel = new Panel();
panel.Dock = DockStyle.Top;
Label label = new Label();
label.MouseHover += Label_MouseHover;
label.Dock = DockStyle.Fill;
label.Text = questionlistItem.Question;
panel.Controls.Add(label);
Controls.Add(panel);
}
//Here (no idea what I just did..)
private void Label_MouseHover(Object sender, EventArgs e)
{
Label label = (Label)sender;
Panel panel = (Panel)label.Container;
panel.BackColor = Color.Red;
}
}
I think you have added your event handler right. The problem is with the line you put in your event handler:
Panel panel = (Panel)label.Container;
Should be
Panel panel = (Panel)label.Parent;
Change the Container into Parent.
Also, I think it is best to use VS designer to test what is the strongly-typed signature of the event handler. In your signature, you use EventArgs. I believe it should be MouseEventArgs instead.
I am creating a graphing program and I would like to allow the user to be able to change the look of the graph they create. Providing them with the opportunity to change the series color, data point size, ect. I am allowing them to do this through the use of a propertyGrid. Through the help of the wonderful people who use stack overflow I was able to import all the properties of a chart into my property grid, however; Now I can't figure out how to connect my chart to the propertyGrid, so when I change something in the grid the chart changes.
So far I have
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
magRadioBox.Checked = true;
PropertyGrid propertyGrid1 = new PropertyGrid();
propertyGrid1.CommandsVisibleIfAvailable = true;
propertyGrid1.Text = "Graph and Plotting Options";
propertyGrid1.PropertyValueChanged += propertyGrid1_PropertyValueChanged;
this.Controls.Add(propertyGrid1);
}
private void Form1_Load(object sender, EventArgs e)
{
this.Text = "MY Plot Program";
propertyGrid1.SelectedObject = chart1;
}
private void button1_Click(object sender, EventArgs e)
{
//some code that is populating my chart(chart1) with data
//....chart1 being filled with data
}
private void propertyGrid1_PropertyValueChanged(object s , PropertyValueChangedEventArgs e)
{
//Getting the MyChart instance from propertyGrid
MyChart myChart = (MyChart)(((PropertyGrid)s.SelectedObject);
//Calling the method that will refresh my chart1
myChart.Invalidate();
}
The above code is for my Form. The my "MyChart" class code is
namespace FFT_Plotter
{
[DefaultPropertyAttribute("Text")]
public class MyChart : Chart
{
public event EventHandler PropertyChanged;
private void OnPropertyChanged(object sender, EventArgs e)
{
EventHandler eh = propertyChanged;
if(eh !=null)
{
eh(sender, e);
}
[BrowsableAttribute(false)]
public new System.Drawing.Color BackColor
{
get { return BackColor; }//Here back color is just an example of a property, not necessarily one that I would make non-Browsable
set
{
base.BackColor = value;
OnPropertyChanged(this,EventArgs.Empty);
}
}
}
}
The class above gets me so far as having a property grid that has all the properties of a chart and allows me to hide those properties as I see fit. However now I am stuck in understanding how to connect my chart1 to the grid I've created. If anyone has any advice on how to do that, it would be incredibly helpful.
You have to add propertyGrid1.SelectedObject = myChartInstance;, then you have to add PropertyValueChanged event listener that will be triggered each time a user changes myChartInstance property via PropertyGrid. So, assuming that you want to redraw the chart each time the change has been done, the code should look like this:
private void propertyGrid1_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e)
{
// Redraw the chart.
chart1.Invalidate();
}
public Form1()
{
InitializeComponent();
magRadioBox.Checked = true;
PropertyGrid propertyGrid1 = new PropertyGrid();
propertyGrid1.CommandsVisibleIfAvailable = true;
propertyGrid1.Text = "Graph and Plotting Options";
// Create your chart.
chart1 = new MyChart();
// Attach your chart to Property Grid.
propertyGrid1.SelectedObject = (MyChart) chart1;
propertyGrid1.PropertyValueChanged += propertyGrid1_PropertyValueChanged;
this.Controls.Add(propertyGrid1);
}
Through the help of the great community on StackOverflow this was the answer I was able to piece together, (standing on the shoulders of giants)
public partial class Form1 : Form {
public Form1()
{
InitializeComponent();
magRadioBox.Checked = true;
PropertyGrid propertyGrid1 = new PropertyGrid();
propertyGrid1.CommandsVisibleIfAvailable = true;
propertyGrid1.Text = "Graph and Plotting Options";
propertyGrid1.PropertyValueChanged += propertyGrid1_PropertyValueChanged;
this.Controls.Add(propertyGrid1);
} private void Form1_Load(object sender, EventArgs e) { this.Text = "MY Plot Program"; propertyGrid1.SelectedObject = chart1; }
private void button1_Click(object sender, EventArgs e) {//some code that is populating my chart(chart1) with data .... //chart1 being filled with data }
private void propertyGrid1_PropertyValueChanged(object s , PropertyValueChangedEventArgs e) {
myChart.Invalidate();
}
This is the code for the MyChart class
namespace FFT_Plotter
{
[DefaultPropertyAttribute("Text")]// This is where the initial position of the grid is set
public class MyChart : Chart
{
public event EventHandler PropertyChanged;
private void OnPropertyChanged(object sender, EventArgs e)
{
EventHandler eh = propertyChanged;
if(eh !=null)
{
eh(sender, e);
}
[BrowsableAttribute(false)]
public new System.Drawing.Color BackColor
{
get { return BackColor; }//Here back color is just an example of a property, not necessarily one that I would make non-Browsable
set {
base.BackColor = value;
OnPropertyChanged(this,EventArgs.Empty);
}
}
}
}
And this declares chart1 to be a MyChart rather than System.Windows...Chart, in the Form1.Designer.CS
...this.chart1 = new FFT_Ploter.MyChart(); ... private FFT_Plotter.MyChart chart1;