I need to implement a program that receives various input data( I do the program in WindowsForms, I made the type selection via button), adds them to a double-linked list, sorts it and outputs it to the listBox). However, when creating a double-linked list object in the button class, this list is not seen by other methods from the form class.(this is logical). I would like to create a template list object in the form and then bring it to a specific type after clicking the button. Is there any way to implement this? For now, all I can think of is creating lists of various types that will end up empty. And the sorting/output call will have to be rewritten for each list.
D_List<int> massiv1;
D_List<int> massiv2;
D_List<string> massiv3;
D_List<string> massiv4;
D_List<double> massiv5;
D_List<double> massiv6;
private void button5_Click(object sender, EventArgs e)
{
massiv1 = new D_List<int>();
massiv2 = new D_List<int>();
Gen<int>(ref massiv1, ref massiv2);
}
//... for each list
private void button7_Click(object sender, EventArgs e)
{
M5<string> sort2 = new M5<string>();
D_List<string> sortedd = new D_List<string>();
string s;
Optim<string>(massiv4, sort2, out sortedd, out s);
listBox1.Items.Clear();
utility.Vivod(ref sortedd, listBox1);
label11.Text = s;
label12.Text = sort2.kolvo_srav.ToString();
label13.Text = sort2.kolvo_perest.ToString();
}
//... for each list
Welcome to stackoverflow!
It's hard to say without code but it seems like you should make use of inheritance for this. Polymorphism is designed to solve this kind of problem.
Your data presumably shares some features (for example, to be sorted it would need some kind of order to be defined). Put these into a base class and inherit that in each of subclasses hat represents the data.
As an example:
class BaseItem: IComparable
{
public int CompareTo (object obj);
}
class DecimalItem: BaseItem
{
public decimal Value { get; set; }
//override CompareTo if necessary
}
Now instead of making a separate list for each type of data, you would make a single list of BaseItems and add whichever type the data actually is to this list.
If you are not using subclasses for your data (eg. they are primitive types) you could probably just make your single list of type IComparable.
Related
So I am a beginner in software development and practicing C# in my time at home.
I have a project that I am working on and have reached a point where I am not sure how to code the functionality.
Imagine in my solution I have a winform UI with a dropdown. Inside that dropdown the user can make a choice and click a button to run a procedure. Depending on what the user has picked, it should initialize the class/object that is picked.
So the dropdown will have options such as; runOptionOne, runOptionTwo. If runOptionTwo is picked in the dropdown, upon clicking the button it will do:
runOptionOne runoptionone = new runOptionOne();
runoptionone.Doaction();
I do not want to have string checks on the dropdown as that will be loads of if statements.
Is there a technique or method to initialize a specific class based on user choice.
Combobox.Items accepts objects. For displaying, their ToString() method will be used.
This makes it possible to access the object directly via SelectedItem. As long as they share a common interface, it's easy to call a method on them.
private void button1_Click(object sender, EventArgs e)
{
var obj = (Interface) comboBox1.SelectedItem;
obj.DoSomething();
}
The other classes:
internal interface Interface
{
void DoSomething();
}
class Class1:Interface
{
public void DoSomething() { }
public override string ToString() => "Option 1"; // TODO: make translatable via resource
}
class Class2:Interface
{
public void DoSomething() { }
public override string ToString() => "Option 2"; // TODO: make translatable via resource
}
And initialization like
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.Add(new Class1());
comboBox1.Items.Add(new Class2());
}
I don't like this approach too much, since I consider the ToString() method to be rather developer oriented.
IMHO, a better approach is to have a dictionary with display strings as keys and objects as values. That way you also get rid of the if-statements and reduce cyclomatic complexity:
private readonly IDictionary<string, Interface> _displayItems = new Dictionary<string, Interface>
{
{"Option 1", new Class1()},
{"Option 2", new Class2()}
};
private void Form1_Load(object sender, EventArgs e)
{
foreach (var item in _displayItems)
{
comboBox1.Items.Add(item.Key);
}
}
private void button1_Click(object sender, EventArgs e)
{
var key = (string) comboBox1.SelectedItem;
_displayItems[key].DoSomething();
}
I have been trying to create a small form application and I wanted to try out binding a DataGridView directly to a collection of objects.
I created the following classes
public class MyClassRepository
{
public List<MyClass> MyClassList { get; set; } = new List<MyClass> { new MyClass { Name = "Test" } };
}
public class MyClass
{
public string Name { get; set; }
}
and I added the following code to a form to test. I based this off of the code in the designer after setting the BindingSource through the UI (while following this walk through https://msdn.microsoft.com/en-us/library/ms171892.aspx)
var tmp = new BindingSource();
tmp.DataMember = "MyClassList";
tmp.DataSource = typeof(MyClassRepository);
When this didn't work I started running through the code behind BindingSource to see what was happening. The setter calls ResetList which tries to create a dataSourceInstance by calling ListBindingHelper.GetListFromType. This call ultimately calls SecurityUtils.SecureCreateInstance(Type) where type is a BindingList<MyClassRepository>. This passes null to args which is passed Activator.CreateInstance which returns an empty collection.
After this ListBindingHelper.GetList(dataSourceInstance, this.dataMember) is called. This method calls ListBindingHelper.GetListItemProperties which results in a PropertyDescriptor for my MyClassList property and assigns it to dmProp.
At this point GetList calls GetFirstItemByEnumerable(dataSource as IEnumerable) where dataSource is the previously created (and empty) instance of BindingList<MyClassRepository> and returns (currentItem == null) ? null : dmProp.GetValue(currentItem);.
The value of dmProp/MyClassList is never accessed and the BindingSource is never populated with the instance I created. Am I doing something wrong? If not is there a bug in the source code? It seems to me like either SecureCreateInstance(Type type, object[] args) should be called and MyClassList should be passed via args instead of the existing call to SecureCreateInstance(Type type) or the value of dmProp should be used regardless?
If that is not correct how do I make the Designers automatically generated code set the DataSource to an instance of the object? Or do I have to inherit from BindingSource? If the latter why does it give you the option to choose a class that does not inherit from BindingSource?
As Reza Aghaei points out, in the designer, setting the BindingSource.DataSource to the “MyClassRepository” may work, however you still need to initialize (create a new) MyClassRepository object. I do not see this line of code anywhere in the posted code: MyClassRepository myRepositiory = new MyClassRepository(); The data source is empty because you have not created an instance of “MyClassRepository” and as Reza points out, this is usually done in the forms Load event.
To keep it simple, remove the DataSource for the BindingSource in the designer and simply set up the BindingSource’s data source in the form load event like below. First, create a new “instance” of the MyClassRepository then use its MyClassList property as a data source to the BindingSource. I hope this helps.
MyClassRepository repOfMyClass;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
repOfMyClass = new MyClassRepository();
bindingSource1.DataSource = repOfMyClass.MyClassList;
dataGridView1.DataSource = bindingSource1;
}
Edit-----
After further review… I agree that you should be able to do as you describe. I was able to get it working as expected with the code below.
BindingSource bindingSource1;
private void Form1_Load(object sender, EventArgs e) {
bindingSource1 = new BindingSource();
bindingSource1.DataSource = typeof(MyClassRepository);
bindingSource1.DataMember = "MyClassList";
dataGridView1.DataSource = bindingSource1;
}
I followed the same steps in the “designer” and it worked as expected. Is there something else I am missing? As you stated… using MyClassRepository mcr = new MyClassRepository() appears to be unnecessary. In addition, if you cannot get it to work using one of the two ways above… then something else is going on. If it does not work as above, what happens?
Edit 2
Without creating a “new” MyClassRepository, object was unexpected and I did not realize that new items added to the list/grid were going into the bindingSource1. The main point, is that without instantiating a “new” MyClassRepository object, the constructor will never run. This means that the property List<MyClass> MyClassList will never get instantiated. Nor will the default values get set.
Therefore, the MyClassList variable will be inaccessible in this context. Example in this particular case, if rows are added to the grid, then bindingSource1.Count property would return the correct number of rows. Not only will the row count be zero (0) in MyClassList but also more importantly… is “how” would you even access the MyClassList property without first instantiating a “new” MyClassRepository object? Because of this inaccessibility, MyClassList will never be used.
Edit 3 ---
What you are trying to achieve can be done in a myriad number of ways. Using your code and my posted code will not work if you want MyClassList to contain the real time changes made in the grid by the user. Example, in your code and mine… if the user adds a row to the grid, it will add that item to the “bindingSource” but it will NOT add it to MyClassList. I can only guess this is not what you want. Otherwise, what is the purpose of MyClassList. The code below “will” use MyClassList as expected. If you drop the “designer” perspective… you can do the same thing in three (3) lines of code... IF you fix the broken MyClassRepository class and create a new one on the form load event. IMHO this is much easier than fiddling with the designer.
Changes to MyClassRepository… added a constructor, added a size property and a method as an example.
class MyClassRepository {
public List<MyClass> MyClassList { get; set; }
public int MaxSize { get; set; }
public MyClassRepository() {
MyClassList = new List<MyClass>();
MaxSize = 1000;
}
public void MyClassListSize() {
MessageBox.Show("MyClassList.Count: " + MyClassList.Count);
}
// other list manager methods....
}
Changes to MyClass… added a property as an example.
class MyClass {
public string Name { get; set; }
public string Age { get; set; }
}
Finaly, the form load event to create a new MyClassRepository, set up the binding source to point to MyClassList and lastly set the binding source as a data source to the grid. NOTE: making myClassRepository and gridBindingSource global variables is unnecessary and is set this way to check that MyClassList is updated in real time with what the user does in the grid. This is done in the button click event below.
MyClassRepository myClassRepository;
BindingSource gridBindingSource;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
try {
myClassRepository = new MyClassRepository();
gridBindingSource = new BindingSource(myClassRepository.MyClassList, "");
dataGridView1.DataSource = gridBindingSource;
}
catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message);
}
}
private void button1_Click_1(object sender, EventArgs e) {
MessageBox.Show("Binding source count:" + gridBindingSource.Count + Environment.NewLine +
"MyClassList count: " + myClassRepository.MyClassList.Count);
}
I hope this makes sense. ;-)
Designer sets DataSource = typeof(Something) for design-time support, for example to let you choose DataMember from a dropdown or to let you choose the data source property from dropdown while setting up data-bindings.
How do I make the Designers automatically generated code set the
DataSource to an instance of the object?
Forcing the designer to do that doesn't make much sense, because the designer doesn't have any idea about what the real data source you are going to use to load data. It can be a web service, a WCF service, a business logic layer class.
So at run-time you need to assign an instance of your list to DataSource. For example in Load event of the form.
I am brand new to C# (I apologise if my question is noobish - I'm teaching myself, so it's a bumpy process). I am trying to develop a winform and since some of the methods are pretty long, I am trying to keep it in a couple classes. This is what I'm kind of hoping to achieve:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1();
}
}
public class longCalculations
{
private void LongMethod1()
{
// Arbitrarily long code goes here
}
}
I'm doing this in an attempt to keep the formMainForm class tidy and be able to split any calculations into manageable chunks. However, I'm encountering problems with using form controls (e.g. check boxes, numeric up-down controls, etc.) in my non-form classes.
If I leave them as is (e.g. CheckBox1) I get a the name does not exist in the current context error. I searched around and I found that it's because that box is defined in a different class. However, if I change it to formMainForm.CheckBox1, the error is now an object reference is required for the non-static field, method or property. Again, I looked around and it appears that that is due to the form initialization method not being static.
If I change public formMainForm() to static formMainForm(), the error now moves to InitializeComponent(); and I do not know where to go from here. I also tried making an instantiation of the formMainForm() method, but that didn't do anything (the code I attempted to use is below. I found it somewhere on this site as an answer to a similar problem).
private void formLoader(object sender, EventArgs e)
{
shadowrunMainForm runForm = new shadowrunMainForm();
runForm.Show();
}
How can I use the formcontrol names in other classes?
P.S. It is my first post here - I am super sorry if I have missed this question already being asked somewhere. I did search, but I didn't find what I was looking for.
EDIT
It seems I hadn't made myself clear - this was just an example of code and my problem is with the second class, not the first one. I have now simplified the code to:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
}
public class longCalculations
{
private void LongMethod1()
{
List<CheckBox> listOfBoxes = new List<CheckBox>();
listOfBoxes.Add(CheckBox1);
// The code displays an "object reference is required for the non-static field, method or property" error at this stage. Changing the "CheckBox1" to formMainForm.CheckBox1 doesn't help
// Arbitrarily long code goes here
}
}
LongMethod1 works perfectly fine when placed in the formMainForm partial class. Moving it to the other form makes it unable to take data from those checkboxes.
I believe this line longCalculations.LongMethod1(); is throwing error cause you are trying to access a instance method as if it's a static method and as well it's defined as private method which won't be accessible outside the class. You need to create an instance of longCalculations class before accessing any of it's member or method(s) and mark the method public like
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations ln = new longCalculations();
ln.LongMethod1();
}
public class longCalculations
{
public void LongMethod1()
{
// Arbitrarily long code goes here
}
}
(OR) If you really want it to be a static method then define accordingly with static modifier like
public class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
Now you can call it like the way you are trying
public static class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
If you're going to make a call longCalculations.LongMethod1();, then you need to make your class static as such.
Or you leave it as not static method by calling
longCalculations lc = new longCalculations()
lc.LongMethod1();
As for accessing controls in separate classes, you can pass in the form and make the controls public which can be dangerous.
So on your Form.designer.cs, change any control you may have to public modifier. Then you would make a call like this...
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1(this);
}
public void LongMethod1(Form1 form)
{
// Arbitrarily long code goes here
form.label1.Text = someString;
//more settings and whatnot
}
Or do something like this:
public class longCalculations
{
public string LongMethod1()
{
// Arbitrarily long code goes here
return myString;
}
}
longCalculations lc = new longCalculations()
string result = lc.LongMethod1();
this.label1.Text = result;
Ideally, your longCalculations class would not attempt to modify the form directly. Instead it would return an object that the form could use to update its controls.
If you need to access the form directly from the longCalculations class, first change the method to accept an instance of your form
public void LongMethod1(formMainForm myForm)
Then you can pass the form itself as a parameter
var calc = new longCalculations();
calc.LongMethod1(this);
In your other class, you need to have an instance of your formMainForm class:
var myForm = new formMainForm();
Then you can access its members like this:
myForm.CheckBox1.Checked = true;
i've often had this issue where i do not really understand how to pass userform variables into classes. for example i have a button:
private void button1_Click(object sender, EventArgs e)
{
DoStuff();
}
and a method in the form class:
DoStuff()
{
Class123 myclass = new Class123();
}
...
...
class Class123
{
//how do i pass for example in myotherClass whether or not my checkbox on the userform is checked? i dont want to have to pass from method to method to class to class. what is the logical/smart way of handling this?
ClassData myotherClass = new ClassData();
}
how do i pass for example in myotherClass whether or not my checkbox on the userform is checked? i dont want to have to pass from method to method to class to class. what is the logical/smart way of handling this?
I think you are looking for function arguments:
// notice the declared function argument isMyCheckboxChecked
DoStuff(bool isMyCheckboxChecked)
{
Class123 myclass = new Class123(isMyCheckboxChecked);
}
private void button1_Click(object sender, EventArgs e)
{
// passing the state of the checkbox to DoStuff as an argument
DoStuff(chkMyCheckbox.Checked);
}
class Class123
{
readonly ClassData myotherClass = new ClassData();
Class123(bool isMyCheckboxChecked)
{
myOtherClass.isMyCheckboxChecked = isMyCheckboxChecked;
}
}
I can see a few things here. The code posted is rather vague, so it is hard to say what the correct answer may be.
If myOtherClass needs to know if a checkbox is checked when the checkbox changes then you should probably look into using a subscriber pattern.
However, if you mean that you just need to know if the checkbox was checked at the moment DoStuff() ran, there is nothing wrong about passing a variable. In fact, passing a variable is the preferred way - it's what variables exist for. That said, you need to pass variables intelligently; if you find that you are just slinging parameters across classes constantly, that's a sign of poorly-designed code. If you need to pass some parameters to myClass to tell it what to do, build them into a (descriptively named) class of their own, and pass that class to myClass's constructor instead of a long list of parameters.
I disagree with this approach.
Any 'smart' method, if it even exist, will break the golden rules of Object Oriented Programming.
An object is a self contained item of data that can only be accessed or changed in a controlled way. This prevents side effects, a common problem in procedural code, where data is globally accessible. In OOP, the objects can receive or send messages to other objects only by calling their methods.
EDIT: To show a way to do it
public static class MyApp
{
public static bool MyCheckBox {get; set;}
}
in your doStuff
MyApp.MyCheckBox = this.checkBox1.Checked;
inside a method of your myOtherClass
if(MyApp.MyCheckBox == true)
...
this is the same as using a global variable in the old days of procedural languages. This paves the way to difficult to track bugs and creates state mode that render an application hard to maintain
I am getting ready to create a generic EventArgs class for event args that carry a single argument:
public class EventArg<T> : EventArgs
{
// Property variable
private readonly T p_EventData;
// Constructor
public EventArg(T data)
{
p_EventData = data;
}
// Property for EventArgs argument
public T Data
{
get { return p_EventData; }
}
}
Before I do that, does C# have the same feature built in to the language? I seem to recall coming across something like that when C# 2.0 came out, but now I can't find it.
Or to put it another way, do I have to create my own generic EventArgs class, or does C# provide one? Thanks for your help.
No. You probably were thinking of EventHandler<T>, which allows you to define the delegate for any specific type of EventArgs.
I personally don't feel that EventArgs<T> is quite as good of a fit, though. The information used as a "payload" in the event args should be, in my opinion, a custom class to make its usage and expected properties very clear. Using a generic class will prevent you from being able to put meaningful names into place. (What does "Data" represent?)
I must say I don't understand all the 'purists' here.
i.e. if you already have a bag class defined - which has all the specifics, properties etc. - why the hack create one extra unnecessary class just to be able to follow the event/args mechanism, signature style?
thing is - not everything that is in .NET - or is 'missing from' for that matter - is 'good' - MS's been 'correcting' itself for years...
I'd say just go and create one - like I did - cause I needed it just like that - and saved me lot of time,
It does exist. At least, it does now.
You can find DataEventArgs<TData> in some different Microsoft assemblies/namespaces, for instance Microsoft.Practices.Prism.Events. However these are namespaces that you might not find natural to include in your project so you might just use your own implementation.
In case you choose not to use Prism, but still would like to try a generic EventArgs approach.
public class GenericEventArgs<T> : EventArgs
{
public T EventData { get; private set; }
public GenericEventArgs(T EventData)
{
this.EventData = EventData;
}
}
// Use the following sample code to declare ObjAdded event
public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded;
// Use the following sample code to raise ObjAdded event
private void OnObjAdded(TargetObjType TargetObj)
{
if (ObjAdded!= null)
{
ObjAdded.Invoke(this, new GenericEventArgs<TargetObjType>(TargetObj));
}
}
// And finnaly you can subscribe your ObjAdded event
SubscriberObj.ObjAdded += (object sender, GenericEventArgs<TargetObjType> e) =>
{
// Here you can explore your e.EventData properties
};
THERE IS NO BUILT-IN GENERIC ARGS.
If you follow Microsoft EventHandler pattern, then you implement your derived EventArgs like you suggested:
public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.
HOWEVER - if your team style guide accepts a simplification - your project can use a lightweight events, like this:
public event Action<object, string> MyStringChanged;
usage :
// How to rise
private void OnMyStringChanged(string e)
{
Action<object, string> handler = MyStringChanged; // thread safeness
if (handler != null)
{
handler(this, e);
}
}
// How to handle
myObject.MyStringChanged += (sender, e) => Console.WriteLine(e);
Usually a PoC projects use the latter approach. In professional applicatons, however, be aware of FX cop justification #CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx
The problem with a generic type is that even if DerivedType inherits from BaseType, EventArgs(DerivedType) would not inherit from EventArgs(BaseType). Using EventArgs(BaseType) would thus prevent later using a derived version of the type.
The reason this does not exist is because what would end up happening is you implement this, and then when you go to fill in the T you should create a class with strongly typed unambiguous properties that acts as the data bag for your event arg, but halfway through implementing that you realize there's no reason you don't just make that class inherit from EventArgs and call it good.
Unless you just want a string or something similarly basic for your data bag, in which case there are probably EventArgs classes standard in .NET which are meant to serve whatever simple purpose you're getting at.