I'm very new to C# and I have a problem filling a combobox when calling the method from another class. My source is like this
class 1
private void btn_login_Click(object sender, EventArgs e)
{
UserControl1 uc1 = new UserControl1();
uc1.fill_cbb();
}
class 2
public void fill_cbb()
{
cbb_table.Items.Add("Text1");
cbb_table.Items.Add("Text2");
cbb_table.SelectedIndex = 0;
}
When I do it that way the combobox is empty.
if it is Asp please take care to the event IsPostBack
Your problem is not calling the method from another class. I suppose UserControl1 is your custom user control, and that the "class 2" you mentioned is a userControl1.
The code would work as it is, but you are calling it on the wrong instance of that control.
In your btn_login_Click method, you are generating a totally new instance of UserControl1. You are of course allowed to do that, which is why Visual Studio would never mark it as an error, but uc1 will not be the control that actually sits in your form.
Let's say in your form you have named the control "cbxOptions". Then in the button click event, you have to write
cbxOptions.fill_cbb();
instead, if that combobox is also of type UserControl1. Then it should work just fine.
Warning, car analogy: It's like when you want a new paint job on your car. Then you buy a new car of the same model and take that to the paint shop, get it painted, then bring it to the junkyard and get it crushed. Your old car will still have the same old color of course.
Related
It's probably a silly question, but I really don't know how to handle it.
My main form default class looks like this:
public partial class MainForm : Form
{
public MainForm(bool version)
{
InitializeComponent();
if(version == true)
{
items_checkedListBox.Items.Add("aa".ToString());
}
else
{
Controls.Remove(items_checkedListBox);
}
}
}
By default, my WinForm app starts with Application.Run(new MainForm(true)); and everything is ok. But I want to update the checkedListBox from another class and for that I need to instantiate my main form object and I call the new object with MainForm mainForm = new MainForm(false); but the problem is that the checkedList control remains, even though Controls.Remove(items_checkedListBox); gets executed.
How could I manipulate a control from another class when I instantiate the main form? :(
By doing this:
MainForm mainForm = new MainForm(false);
you create a new second form of the type MainForm and delete it's control items_checkedListBox, but that's not the control which you see on your first form of MainForm. Furthermore you don't see the second form you created, because you didn't make it show up, so don't wonder that you don't see anything happening like the removal of the other control on the second form.
So in order to manipulate your control items_checkedListBox you need to pass the reference of this control to your class in which you wish to manipulate it.
Imagine you would have another form (which is your other class), which you use to manipulate your control items_checkedListBox.
public partial class FmManipulateControl : Form
{
public FmManipulateControl()
{
InitializeComponent();
}
}
In order to be able to do this, pass a reference of this control as method parameter to the constructor:
public FmManipulateControl(Control myControl) { ... }
So that we can manipulate it we store this reference of our control in a field, so e.g. a button click event can access the control to change/remove/... it.
Control controlToChange;
public FmManipulateControl(Control myControl)
{
InitializeComponent();
controlToChange = myControl;
}
Let's imagine we bind to a button click event in our form FmManipulateControl:
private void button1_Click(object sender, EventArgs e)
{
//diposes the control, so it does not exist anymore, but you can apply
//any change to the control you wish to do
controlToChange.Dispose();
}
Now all you have to do is to create an instance of FmManipulateControl and pass it a reference of the control items_checkedListBox and show the new form object.
FmManipulateControl fmChangeAControl = new FmManipulateControl( items_checkedListBox);
fmChangeAControl.Show();
Further explaination about the reference type:
I am talking about passing a reference of the control and I think you might wonder about what I mean by that. I suggest you to read about value and reference types.
I try to keep it short and simple.
Imagine a value type contains the value directly itself: e.g. an int. The object contains the value directly.
int a = 3;
a contains the value 3.
Now let's have a look at our control. This ListBox control items_checkedListBox does not contain our object control, but a reference to it's location in memory. That's why it is called reference type.
So when we pass items_checkedListBox as a method parameter, we don't pass an object, but the memory location of our items_checkedListBox control. So we point to the same object, so we are abel to manipulate it.
Note:
Method parameters are just a copy of the inputted object, so when we do:
FmManipulateControl fmChangeAControl = new FmManipulateControl( items_checkedListBox);
In our form fmChangeAControl we got an object(myControl) which is a copy of items_checkedListBox. But since we did not pass the object, but a reference it does not matter if we have a copy or not, we still point to the same memory location so we still manipulate the same object.
I'm making a game library with C#.
I have a main Form which has a FlowLayoutPanel, which hosts the game library. There is an "add game" method in main Form which adds an item to FlowLayoutPanel, but this method is being called from a second form. But when I'm calling this method from this second form, nothing happens at all, but it works, if called from the main form.
Here's the code:
Here's the add game method in mainForm:
public void addIso()
{
PictureBox gameBox = new PictureBox();
gameBox.ImageLocation = "link here";
gameBox.Height = 200;
gameBox.Width = 150;
gameBox.SizeMode = PictureBoxSizeMode.StretchImage;
isoPanel.Controls.Add(gameBox);
}
This method adds a placeholder game to FlowLayoutPanel called isoPanel. Works when called from the same form.
And here's how the method is being called from second form:
private void addGameButton_Click(object sender, EventArgs e)
{
MainWindow mainForm = new MainWindow();
mainForm.addIso();
}
When I tried to add simple message box in the method, message box did show, but game wasn't added to FlowLayoutPanel.
Any tips or solutions?
I apologize for my poor english and messy programming terms, I started learning C# a little while ago.
You can achieve this by using delegate and Delegate.
What you are doing wrong here:
From addGameButton click event you are creating a new instance of the mainForm. Which is not the actual main form that you are currently seeing, its a different instance of the mainForm. your code adds the control to the layout just confirm this by calling mainForm.Show() this will opens a new form with the control.
What you can do:
In such cases, you want to modify the parent control, calling methods in parent class, you need to use delegates by the following way:
Changes needs to apply in the Parent class ie., MainWindow.
Define a delegate and an event of that delegate type.
public delegate void UpdateUiDelegate();
public event UpdateUiDelegate UpdateUiEvent;
Assign the required method to the Event(better use this in constructor):
public MainWindow ()
{
UpdateUiEvent+= new UpdateUiDelegate(addIso);
}
Next work is in the child form ie., Form2 (use a better name let it be ImageChildControl). Create a Delegate there:
public Delegate ControlCreator;
Come back to MainWindow, Locate the place where you are calling the Second form, after creating instance of the child form assign the created event to that Delegate of the instance, for that Use the following codes there:
ImageChildControl ImageChildControlInstance = new ImageChildControl();
ImageChildControlInstance.ControlCreator = UpdateUiEvent;
One more work to do in child form that is; Calling the delegate from the Button click event. ie.,
private void addGameButton_Click(object sender, EventArgs e)
{
ControlCreator.DynamicInvoke();
}
Now you can see your code works as you expected.
You seem to be recreating the form when you load the second form.
as this does lack a little context.
I suggest you have a main tread which will run the two forms
create a game manager class Ex: GameManager.cs
In the class create a variable for both forms and set them as protected.
in each form send a reference of the gamemanager to it.
which will allow each window to communicate with each other through the manager by provide secure inter communication.
Let me know if you would like some source with this.
I cannot get my head around this probably simple task, i have 2 forms, my main and a "footprints" one, in the footprints, i have a combobox with various .txt files loaded in, once i select a combobox value i'm trying to send the value to a label on form 1 the main one.
code for form 2:
private void btnUpdateFootprints_Click(object sender, System.EventArgs e)
{
if (File.Exists(#"LogicFiles\footprints.txt"))
{
// add footprints and add to .txt box
File.WriteAllText(#"LogicFiles\" + comboBoxUseFootprints.Text, txtBoxFootprints.Text);
FormMain.lblFootprintsUsed.Text = comboBoxUseFootprints.Text;
this.Hide();
}
}
This part "lblFootprintsUsed.Text" is the name of the label on form 1, the above code is in a button, once clicked it should hide and update the label, i'm getting:
An object reference is required for the non-static field, method, or property 'FormMain.lblFootprintsUsed'
I tried a few things but to be honest i never fully got how to reference form 1 without making a new form instance.
thanks for any help guys
Graham
FormMain.lblFootprintsUsed
This code is trying to set the static label of FormMain. However (correct me if I'm wrong) you have no static method in that form.
I guess that FormMain is the one that creates the footpronts form. In order to actually update the label of the main form you should raise an event from the footpronts form with the new value and subscribe to it from the main form.
http://www.codeproject.com/Tips/55555/Pass-value-between-forms-using-events
On my form I have 2 UserControls (ButtonDiscount, ButtonAdvertisment) that inherit FadeControl. FadeControl inherits UserControl class and is used to do custom stuff on the controls like fade out.
My 2 UserControls each have just one button hence those two unimaginative names.
On click of that button on one of usercontrols, I need to access the method in FadeControl from the other UserControl. The other button does the opposite.
I've done the following, on the event click in the UserControl ButtonDiscount:
private void button1_Click(object sender, EventArgs e)
{
ButtonAdvertisment ba = (ButtonAdvertisment)this.Parent.Controls.Find("buttonAdvertisment1", true)[0];
ba.FadeOut(true);
}
It works like a charm, but I don't think this is the right way, is there another way to access the method from the parent class of the other UserControl?
I can't pass it thru a UserControl constructor, the designer breaks down every time.
You have 2 separate user controls which are not aware of each other, which is good and keeps your code loosely-coupled. Now what you are trying to do is to make them somehow know about each other and communicate. Making them aware of each other breaks the loose-coupling and is a bad design.
What I would suggest is creating a 3rd control which will hold the two together and will handle all the communication between them. Each of your original controls will have public events, to which the parent control can subscribe and handle appropriately.
Check mediator pattern for more info: http://en.wikipedia.org/wiki/Mediator_pattern
What you've done is fine - you could do it by exposing events that fired when you click the button in those controls, and then passing references to each other (subscribing to those, writing the code to fade 'this' control).
That might be a bit too much work for a simple solution, however.
What I would say about your solution is that if you were to change the name of control(s) then it stops working. You could instead do:
var ba = this.Parent.Controls.OfType<ButtonAdvertisement>().FirstOrDefault();
That way you're no longer tied to the control name - but the type of the control. You'll need a using System.Linq; in your code file for this to work. Of course, this relies on the fact that there is only ever one other instance of that control type in the parent.
If you're interested in the first solution I mentioned - then this code snippet should help demonstrate:
public class FadeControl {
public event EventHandler Clicked;
public void FadeOut(bool b){
}
public void AttachTo(FadeControl other){
//splitting this operation to a public and private allows us to
//initiate an attach publicly, but then recurse privately without
//causing a stack overflow
AttachToInternal(other);
other.AttachToInternal(this);
}
private void AttachToInternal(FadeControl other){
other.Clicked += Attached_Clicked;
}
protected virtual void Attached_Clicked(object sender, EventArgs e)
{
//fade me out
FadeOut(true);
}
// provides a way for the deriving class to raise the Clicked event
protected void OnButtonClicked(){
if(Clicked != null) Clicked(this, null);
}
}
public class ButtonDiscount : FadeControl {
Button _button;
//omitted: designer code
//this is your handler for the _button clicked event
private void _button_Clicked(object sender, EventArgs e){
//call the base class' OnButtonClicked method - to raise the event
OnButtonClicked();
//TODO: do work.
}
}
//omitted - code for the ButtonAdvertisement class
Once you have that done - in your form, assuming you have _buttonAdvertisement and _buttonDiscount members in your form and after they're initialised - you simply do:
_buttonAdvertisement.AttachTo(_buttonDiscount);
And that will immediately bind both controls to each other.
Note - in response to a comment below - I've made the event handler in FadeControl for another FadeControl's Clicked event protected and virtual - so you can override it.
I was wondering if it is possible to have a user control open a winform that allows a user to select options on it and then when he closes the form - the options / values he selected are returned to the user control?
Why not create some public properies on your dialog form, and access them from the UserControl once the dialog has been closed?
public class OptionsForm : Form
{
// ...
public string Option1 { get; set; }
public bool Option2 { get; set; }
}
And then, within the UserControl:
public void ShowOptionsForm()
{
using (var form = new OptionsForm())
{
if (form.ShowDialog() == DialogResult.OK)
{
var option1Value = form.Option1;
var option2Value = form.Option2;
// use option values...
}
}
}
Please consider this answer as an "extended comment" on Steve Greatrex's now-accepted answer : it's too long for a comment, and I want to demonstrate a few options, add a few "flavours" to the taste. This is not at all a "criticism" of Steve's answer which, imho, hit the "bullseye."
Assumptions : if I had read the question earlier, I would have queried the OP via a comment on each of these points :
the OP did not specify whether the Form to be "shown" was to be shown modally or not.
the OP did not specify whether the Form was to be re-created each time it was shown, or whether one instance of it should be created and re-used.
the OP wrote "open a winform that allows a user to select options on it ... snip ... "options / values he selected are returned" : Steve's code does not show exactly how the Properties exposed as Public are set, but I'm going to assume that the OP probably intended to mean that the user interacted with some Controls on the shown Form, and that the "options / values" he refers to are Properties of Controls on the Form : like the end-user typing some text in a TextBox, or the selected indexes in a ListBox with its SelectionMode set to allow one of two choices of multiple selection.
the OP does not say if it's desireable that the Form (if used repeatedly) retain the results of the last interactions of the end-user with the Controls on the Form as described above.
the OP says nothing about whether the Form shown by the UserControl has its Parent property set to some other valid container : I'll assume they meant the Form to be displayed "parent-less."
Comments :
if the OP intended the Form to be shown modally : in order for Steve's code to work, the 'ControlBox of the Form would have to eliminated as an option, and a Button put on the Form whose 'DialogResult property was set to "OK," and whose 'Click Event closed the Form : without those conditiions being met the result of ShowDialog in Steve's code would never return "OK," and the properties' values would never be set. Note : closing a Form via the 'ControlBox will return a DialogResult of "Cancel."
re-use of the shown Form : if we assume the Form will probably be re-used, then why not create it once and 'Show and 'Close as necessary ? Let's consider the possibility that there may be good reasons to expose the created Form as a Public member of the UserControl.
Consider the following alternative idea : trying to present a solution as "different" as possible from Steve's : just to demonstrate, explore, the options.
Our "shown Form" will have a TextBox and a ListBox that allows multiple selections : our goal is to expose the Text in the TextBox and the current selection of Indices in the ListBox.
Form has a ControlBox : does not require a Button to close as described above.
it doesn't matter if the Form is shown modally or not : will set properties the same way in either case.
the Public properties to be set are to be based on reading the current state of Controls on the shown Form.
the Form is created once and exposed as Public : because of this a "side-effect" is that when the Form is re-displayed it will retain the previous results of what the user selected, etc. Of course there are other ways you could easily control that in your code to make one or all of the Controls "virgin" again.
in The "shown Form" which we have named 'DataEntryForm :
Just as Steve shows we define public properties to expose ;
public string TextEntered { get; set; }
public ListBox.SelectedIndexCollection LBSelection { get; set; }
In the Form Closing Event we update the properties based on the state of the Controls :
private void DataEntryForm_FormClosing(object sender, FormClosingEventArgs e)
{
TextEntered = textBox1.Text;
LBSelection = listBox1.SelectedIndices;
}
in the UserControl we create a public property of type 'DataEntryform (reason why to be explained)
public DataEntryForm theDataEntryForm { get; set; }
We create an instance of the DataEntryForm in the Load Event of the UserControl and assign it to the public Property
private void UserControl1_Load(object sender, EventArgs e)
{
theDataEntryForm = new DataEntryForm();
}
At this point we will leave it to the OP's (and your) imagination to picture when the instance of the DataEntryForm is shown. But of course we want to demonstrate how you would access the properties after the Form has been closed : so we put a Button on the UserControl :
private void button2_Click(object sender, EventArgs e)
{
Console.WriteLine(theDataEntryForm.TextEntered);
Console.WriteLine(theDataEntryForm.LBSelection.ToString());
}
Note : we didn't do any "fancy" analysis of the ListBox selected indices : but we could have written out whether it was null, or how many items had been selected, etc.
Also : we didn't deal with the issue of what if the OP wants to take some action the moment the "shown Form" is closed : that's so simple : you just subscribe to the FormClosed event of the Form in the UserControl, and do what you need to do in your Event Handler code.
Finally we come to the question of why make a Public Property of type 'DataEntryForm :
Well, just consider that by exposing that "shown Form" via a Public Property in the UserControl : we allow the potential containers (probably a Form) of the UserControl instances to also have access to the values of the Controls on the "shown Form" ... which may be valuable, may save us some duplication of properties.
So, if UserControl1 is on Form1, and Form1 wants to know the Text value of the TextBox on the "shown Form" : it could be accessed like so :
this.userControl11.theDataEntryForm.TextEntered
Edit : A friend of mine wrote me to express his opinion that allowing a "higher-level" container to directly access a "component" embedded in a UserControl was a "violation" of good OOD practicem and breaks encapsulation : he issued me a moving violation ticket :) So, keep his warning in mind. From his point of view the properies should be duplicated in the UserControl with different names, and only those UserControls properties made available to the UserControl Container. My bias is to see the "UserContro/Form" as one "compound object" here, which, since the Form is exclusively used by the UserForm, justifies not duplicating the Properties /Edit
Of course we've left out checking for possibly null values of everything-under-the-sun as we all do so religiously.
here's a short example on how you could do it. It's not complete you'll have to fill in some of the blanks but it should give you an idea of how to solve your problem.
this code goes where you construct your control and you form
MyUserControl ctrl = new MyUserControl();
Action<typeYouPassBack> callBack = myUserControl.FormCallBack;
MyOptionForm form = new MyOptionForm(callBack);
the form class would then have to look something like this: (important part is the action argument)
class MyOptionForm : Form
{
private readonly Action<typeYouPassBack> _callBack;
public MyOptionForm(Action<typeYouPassBack> callBack)
{
_callBack = callBack;
Close += form_Close;
}
privatre void form_close(object sender, EventARgs e)
{
typeYouPassBack postBackData = //populate the postback data
_callBack(postBackData);
}
}
the type Action is simply a delegate with the signature void f(T arg). In the above code it's expected for the user control to have amethod called 'FormCallBack' which of course can be named anything you like as long as you use the correct name when assigning it to the 'callback' variable