I'm very new to using C#. If you have ever heard of the Karol the robot program that is written in Java then that's what I'm aiming to build.
But I am stumbling at almost the first hurdle, I want to make a class for Karol (It is just a picture) that can move around the screen in blocks of 32x32 squares.
Trouble is when you create a class you can't access the properties of form objects because they are separate things.
I would like to be able to manipulate form objects from my class but without having to pass the object through the method each time I use it.
Any help is much appreciated.
Do not need to pass a reference of the Form every time. Should be enough to do something like this:
`public class Karol
{
private Form _form=null;
public Karol(Form frm) {
_form = frm;
}
// after use _form inside the functions and properties of the class, where needed
}`
edit
to acces a control data inside a Form it needs to expose or controls itself, like
public Label MyFormLabel {....}
Or expose a functions/properties that sets or gets the data from the control.
public string MyFormLabelText { get{ return label.Text;} set{label.Text = value;}}
If it's just one form object that "Karol" is manipulating, you should be able to pass it to the constructor and save it for use in later member calls. That way you only pass it once at construction time.
Related
I have a Form class
partial class ProgressMainForm : Form
{
public ProgressMainForm()
{
InitializeComponent();
}
}
And then a class that uses that class and contains all functionality for the user
public class ProgressForm
{
public ProgressMainForm myProgressForm;
public ProgressForm(string title)
{
myProgressForm = new ProgressMainForm();
myProgressForm.Text = title;
}
public void SetProgressBar(int min, int max)
{
....
}
I then use this ProgressForm class in my project like this
progresswindow = new ProgressForm("Replacing All Strings");
This way progresswindow only contains members that are related to the functionality of the ProgressForm and all those Form members are hidden from the user.
But sometimes I need to access those Form members, for example when I need Invoke method.
Is there a way to make myProgressForm in ProgressForm accessible to users without making ProgressMainForm public?
Or is this approach wrong?
In my opinion you should not work with the form directly. If I read your setup correctly, you want to show progress indicator while some job is being done. ProgressForm should expose methods to set the counters and increment them; as you run it on another thread, form manipulation should be done from inside the methods of ProgressForm. Your Invokes belong there, wrapped in suitable methods. If you want to change some visual properties of ProgressMainForm relay those properties to ProgressForm.
To resume, calling code should have no clue what ProgressForm does other than setting progress boundaries, starting, setting current percentage and stopping. This way, if you are asked to port the application to another UI system the amount of code you will need to change will be drastically reduced.
Is there a way to make myProgressForm in ProgressForm accessible to users without making ProgressMainForm public?
Yes, you can create some public properties on ProgressForm that expose specific properties of ProgressMainForm.
private ProgressMainForm myProgressForm;
public int SomeProperty
{
get { return myProgressForm.IntProp; }
set { myProgressForm.IntProp = value; }
}
For readonly properties, omit the set, and for any types that are reference types, you may want to return a clone or copy (to ensure the client can't change it).
Wrap or Expose the Methods you need. But somehow i don't like the approach, restricting the access is not a bad idea but should not be the whole purpose of this kind of abstraction. Try to make the acess easier, not restrictive.
You can declare the methods as internal , This will allow you to call the methods from within the assembly.
I need to write the result of my query in a textbox in the main form, from another class. What is the best and easy way to achieve this?
Your external class should not know anything about a textbox. It may know about your form in order to send the result there, but the elements are belong to the form and should not be exposed (it is what is called encapsulation).
I suggest you to have a meaningful method on your form, something like ShowListOfUsers(users), or whatever you do, call it appropriately so it can be understood externally.
Then in this method you put the result into the controls (textbox) as you want it.
I also suggest you to have an interface for the form which will contain such behavioral methods and have your window implemented this interface, something like:
public interface IOrderView
{
void ShowOrderDiscount(result);
}
so your external class will know only about the interface, not about the window, the textbox, etc.
Now your query component is trivial:
public class SomeOperation
{
private readonly IOrderView _view;
public SomeOperation(IOrderView view)
{
_view = view;
}
public void DoSomething(parameters)
{
var result = GetMyComplicatedResult();
_view.ShowResult(result);
}
}
The code above is not ideal (as I don't know what is your scenario), but the idea is there.
Good Luck.
Use a public property (or a getter) in your class to retrieve the output of the query.
I have a C# class question which I hope to get some help with. I have one class called CountdownUserControl. There are a number of functions within this class. I then have another class called Min. There are certain things I need in this form within CountdownUserControl class so I create an instance of it within CountdownUserControl:
public partial class CountdownUserControl : UserControl
{
//-----------------------------------------------
// Private data members
//-----------------------------------------------
private Min _Min = new Min();
However within the Min class I also would like to use a function which is contained within the CountdownUserControl class - however I cannot create an instance of it within the Min class such as
public partial class Min : Form
{
private CountdownUserControl CU = new CountdownUserControl();
so that within Min class I could do CU.Method_I_want();
as this will give a stackoverflow. Does anyone know a solution around this? Thanks for your time.
Classes and methods
Classes shouldn't just been seen as a collection of methods, when they are created ('instantiated') with new, they become actual objects that should be treated as such.
You need to re-think your strategy and instead simply reference a Min or CoundownUserControl object. What does each one represent? You are suggesting that the UserControl (a part of a Form) needs to have its own Form created for it - that's not the case. The Form is the object that creates the UserControl. The UserControl can access the Form by using the ParentForm property.
The StackOverflow
When you do this: new Min() you are creating a new Min object. Then, in Min, when you do this: new CountdownUserControl() you are creating a new CoundownUserControl object. Which in turn creates a new Min object, and so on and so forth.
How to fix your problem
Simply put, use Min min = (Min)this.ParentForm; within the user control if you are sure the user control is on a Form whose type is Min.
And finally/additionally, you should not create the instance of CountdownUserControl yourself unless you are going to set the properties and add it to the Controls collection of the form within your code. Instead, build your project, drag-and-drop the CountdownUserControl onto your form - a property to access the control will be created on your Min class automatically, called countdownUserControl1.
All these answers are great, but you should also consider the fact that cyclic dependencies are generally really difficult to work with. Your classes should be somewhat isolated units with a single purpose. They should be loosely coupled from each other. If you redesign your classes to eliminate cyclic dependencies and follow these guidelines, you will write better and more maintainable code in general and will have less issues like this in the first place.
There surely are plenty of solutions to this. An easy one would be to pass the current Min to CountdownUserControl in its constructor (or vice versa):
private Min min;
public CountdownUserControl(Min min)
{
this.min = min;
}
When you are facing these kind of problems, there probably is something wrong with your class structure, though. Maybe you could split some of the functionality out of your classes into a new one to avoid this problem.
Instead of instantiating a new Min class every time, you could set the value of it in a constructor.
public CountdownUserControl(Min min)
{
_Min = min;
...
Is CountdownUserControl going to be on the Form Min? Why would you instantiate the form from the control, and not the reverse? Shouldn't the Countdown control be on the form? Then you could instantiate the form, initialize the control, and then access the function.
The problem here is that whenever a CountdownUserControl is created, it tries to create a new Min, but whenever a new Min is created, it tries to create a new CountdownUserControl. This process could continue indefinitely and therefore the stack is blown.
The solution is to inject the instance of CountdownUserControl into Min (Or vice versa, depending on what gets created first).
So CountdownUserControl will look like this:
public partial class CountdownUserControl : UserControl
{
//-----------------------------------------------
// Private data members
//-----------------------------------------------
private Min _Min;
public CountdownUserControl(Min min)
{
_Min = min;
}
...and Min will look like this:
public partial class Min : Form
{
private CountdownUserControl CU;
public Min()
{
CU = new CountdownUserControl(this);
}
Do not create a form in the user control. Add it as a dependency:
public partial class CountdownUserControl : UserControl
{
private Min _Min;
public CountdownUserControl(Min parentForm);
And then use it in your form:
public partial class Min : Form
{
private CountdownUserControl CU;
public Min()
{
CU = new CountdownUserControl (this);
}
Update
A more suitable solution would be to break out the common functionality from the two classes and put them in separate classes. Read up on single responsibility principle. I got a post about it in my blog.
You can pass in an instance of your CountdownUserControl to your Min class (via an additional constructor parameter or via a property).
public partial class Min: Form {
public Min() {
InitializeComponent();
}
public CountdownUserControl Countdown {get;set;}
}
Since this is a form you probably want to go with the property so as not to break the designer.
I won't speak to whether or not this is proper form (hopefullt you are using something like PresentationModel or MVC), as I do know tehre are times code like this is required.
Now as has been pointed out, if you plan on showing the user control in the form then a different solution should be adopted. But it all depends on how you are planning on what you are doing with the form. If you are for example showing teh form in a dialog keeping a class level reference is a bad idea since once closed the form will be disposed.
A little more detail would get you closer to a fully correct answer.
However within the Min class I also would like to use a function which is contained within the CountdownUserControl class - however I cannot create an instance of it within the Min class such as
Is it really necessary that mentioned function is member of CountdownUserControl?
Could you reveal more of public interface of your classes?
If the function has no reference to instance of CountdownUserControl consider changing it to static. Else try to design new class named e.g. CountdownState whose instance may be shared among both CountdownUserControl and Min.
I have a checkbox that I created to windows forms, how can I set it to static?
public static CheckBox checkthis;
This code creates a new one as static, what I want to do is set one that I have created in the designer to static.
Update:
I tried below answer and it worked, though the checkbox disappeared from the form and various other issues kicked in. Instead I did this create a new one and did this:
public static CheckBox checkthisnew;
...
checkthisnew = checkthis;
Either way, I have now realised that I am fail and that I just can use the state changed on the events list, so all is well...
Sorry for not making my reasoning behind this more clear, I do appreciate your answers though, thank you.
Edit the MyForm.Designer.cs file, right where the declaration for your checkbox is. Note that your changes will be reverted if you use the designer to modify the UI again so you'll have to do this again.
Nothing good can come from making a dependent UI control static. It's one thing to make a component static and that could be ok, but for something like a CheckBox, you're just asking for trouble. For starters, a single control can only have one parent. So you can't just make a single instance of your control and expect to be able to add it to multiple forms and everything will magically appear to be in sync. If you need to share some values, do it the right way and bind to them, register some events, share the value and not the control that holds the value, or other similar methods.
I also cannot recommend you modify generated files (especially if it's generated from a tool you're using all the time). If you must insist on making the control static, declare it in your source file for the class, not the designer-generated file, the classes are declared partial for a reason.
You're probably trying to share some bool value that the CheckBox represents. Make that a static property.
public partial class MyForm : Form
{
public static bool IsToggled { get; set; }
}
If somewhere down the line you want to tie that to an event or whatever, you could always change the implementation of the accessors.
Hmm... without more context, I'd suggest to use a public boolean property for this.
Having a UI item be static is not a good idea.
Try something like this:
public class MyForm : Form
{
public static bool IsWhateverSet {get; private set;}
}
I have a C# class library which uses a form (which is also in the library). Let's say I have an edit box on this form called editContents. In a regular form application, I'm used to being able to aquire the edit box like this:
class MainForm
{
void Method()
{
this.editContents.Text = "Hi";
}
}
I guess some magic occurs behind the scenes in a regular forms application, because the edit box member is private in the MainForm class, but I can still access it like a public member.
But in my class library I can't access the edit box like this. I instantiate and show the form "manually" like this:
form = new MyForm();
form.Show();
How do I properly acquire the editContents control from this form?
You could make it a publicly accessible Property, by adding some code like this:
public String EditContents // for just the "Text" field
{
get { return this.editContents.Text; }
set { this.editContents.Text = value; }
}
Or:
public TextBox EditContents // if you want to access all of the TextBox
{
get { return this.editContents; }
set { this.editContents = value; }
}
The "magic" is that a field is generated for your textbox in the *.Designer.cs file. By default, this field is private. If you want to change it's accessibility, select your text box in the forms designer, and change the "Modifiers" property to Public.
This might however not be a good idea to expose publicly all controls of your form. You can instead wrap it around in a property like Donut suggests, which is cleaner.
Private members are accessible within their declaring class. That's why you're able to access editContents from within MainForm.
Private members are inaccessible from outside their declaring class.
(it's the definition of private, there is no magic)
You can wrap it in a public property:
public TextBox EditContents
{
get { return this.editContents; }
}
In the first instance, you are able to access editContents because you are within the scope of the form.
As #Donut has said, you can expose a property for users of your library to play around with the control. If you want to limit the access, you could write a method instead.
e.g.
void SetContentForEditor(string text)
{
editContent.Text = text;
}
And, you can then make a call to SetContentForEditor
e.g.
myForm.SetContentForEditor("hello world");
You could aquire it through the Controls collection.
form.Controls.Find("nameOfControl", true);
The difference in accessing the form member inside the Method() function vs via the form reference in your last snippet is that your Method() function is a member of your form's class, and therefore is allowed to access other private members of the class.
I would introduce an event in the library which notifies all subscribers to this event when a change happens to the text and should be set in the form. The form should attach to this event and set the textbox content on its own.