C# Editing parameters of user objects in listBox - c#

How can I edit parameters of my objects added to ListBox?
Already I have something like this:
public class Car
{
protected double aa;
protected string n;
public Car(double aa, string n)
{
this.a = aa;
this.n = n;
}
public virtual double Speed()
{
return 0;
}
public class Car111 : Car
{
public double A { get; set; }
public string Name { get; set; }
public Car111(double aa, string n)
: base(aa, n)
{
A = aa;
Name = n;
}
public class Car222 : Car
{
public double A { get; set; }
public string Name { get; set; }
public Car111(double a, string n)
: base(aa, n)
{
A = aa;
Name = n;
}
public override string ToString()
{
return Name;
}
listBox1.Items.Add(new Car111(aa, "MyCar")); //add obcject to listbox
listBox1.Items.Add(new Car111(aa, "MyCar")); //add obcject to listbox
private void button5_Click(object sender, EventArgs e)
{
Car111 item = (Car111)listBox1.SelectedItem;
if (item != null)
item.A = Convert.ToDouble(textBox8.Text); //There is a problem
}
}
}
}
A don't know what to do to change "aa" parameter in Car111 and Car222 class. How can I add the summary Speed of Cars being adding to listbox?

I'm not entirely sure I understand your question and the fact that the code you have provided doesn't compile makes it a bit more difficult, however I'll take a stab at it... There are 2 things I can think of that you may be asking/having trouble with
FIRST
Let's start with the end of your post:
A don't know what to do to change "aa" parameter in Car111 and Car222
class. How can I add the summary Speed of Cars being adding to
listbox?
I don't see anything in your code that refers to speed, other than a virtual method that always returns 0. Based on the context of your question, however, I'm guessing that perhaps you are using aa from the base object, Car. Next, I'd like to look at your last line of code:
item.A = Convert.ToDouble(textBox8.Text); //There is a problem
Note that you are not setting aa here, you are setting A. If you are trying to expose aa with A, then instead of declaring A as
public double A { get; set; }
you would instead need to do this:
public double A { get{return aa;} set{aa = value;} }
The reason for this is because when you use auto-properties, the compiler creates a backing variable in the background for you; obviously, it isn't going to know that you want it to be backed with aa (or anything else) unless you tell it so. Note that this applies to n and Name, too.
While we are on the topic, if all of your derived classes are going to have an A and Name the expose aa and n, respectively, then you might as well put them in the parent class.
SECOND
Looking at the first line of your question:
How can I edit parameters of my objects added to ListBox?
I think you are saying that you want the listbox to show a new value. If that is the case, I would question how you are displaying your car data in the listbox. When you execute line of your code,
listBox1.Items.Add(new Car111(aa, "MyCar")); //add obcject to listbox
The listbox would add an item, but unless there is some work going on that you are not showing us, then what would show up is <yourAssemblyName>.Car111 (unless Car111 is also supposed to have a ToString like Car222, in which case you would show the name, "MyCar".)
Either way, when you call
item.A = Convert.ToDouble(textBox8.Text); //There is a problem
That isn't going to update anything your listbox is showing.
Suggestion:
I don't see anything in your example that necessitates the added complexity of inheritance. Perhaps there is more that you are not showing, but based on what you have here, and based on the assumptions I have made, I would refactor your code to look something like this:
public class Car
{
//update aa, n, and A to reflect what they represent.
//I'm guessing that n represents "name" and "aa" represents "speed"
//Unless you need inheritance, you can use private instead of protected
private double _speed;
private string _name;
//I'm guessing "A" represents "Speed".
public double Speed
{
get { return _speed; }
set { _speed = value; }
}
//This was in your base class, but you don't need it if
// "Speed" (what was "A") will work up here
//public virtual double Speed()
//{
// return 0;
//}
public string Name
{
get { return _name; }
set { _name = value; }
}
//parameters should reflect what they represent, as well
public Car(double speed, string name)
{
this._speed = speed;
this._name = name;
}
public override string ToString()
{
//return Name;
//If you want to show the name and the speed in the listbox
//you could use the following:
return string.Format("{0} is going {1}", Name, Speed);
}
}
Then you can add it the way you were, except w/o inheritance (unless needed):
listBox1.Items.Add(new Car(travelingSpeed, "MyCar")); //add object to listbox
listBox1.Items.Add(new Car(travelingSpeed, "MyCar")); //add object to listbox
Finally, unless you have data binding going on, if you simply update the object, the listbox won't update. You will need to tell the listbox to update. Here is one way to do that:
private void button5_Click(object sender, EventArgs e)
{
Car c = (Car)listBox1.SelectedItem;
if (c == null)
return;
if (!Double.TryParse(textBox8.Text, out c.Speed))
return;
int idx = listBox1.Items.IndexOf(listBox1.SelectedItem);
listBox1.Items.Remove(listBox1.SelectedItem);
listBox1.Items.Insert(idx, c);
}

Related

C# Abstract methods, readonly properties

I have an assignment (bunch of oop stuff, polymorphism and inheritance) and amongst other things I have to do the following:
I need to add an abstract method to the class Vehicle (called calculateOccupancy()) which has to return the % of the leftover space in a vehicle. I then have to implement that in my derived classes. The issue here is, I have 3 derived classes, two of them have 2 attributes and one has 3. So how do I make my abstract method, so that it can accept 2 or 3 arguments.
I have to add a unchangeable property to the class Person, and the property has to return the first letter of the name and surname, divided by a dot.
namespace Example
{
abstract class Vehicle
{
//class member variables, most likely unnecessary for the questions
private Person driver;
private string vehicleBrand;
private string vehicleType;
private double fuelConsumption;
private double gasTankSize;
private string fuelType;
//the default constructor
public Vehicle()
{}
//The abstract method from question 2
// how to make it so that it wont error when I need to
//put in 3 variables instead of two, meaning, how would I add int c
public abstract double calculateOccupancy (int a, int b);
//The derived class that implements the method
class Bus : Vehicle
{
private int allSeats;
private int allStandingSeats;
private int busPassengers; //the number of passengers
//the constructor
public Bus (int a, int b, int c)
{
allSeats=a;
allStandingSeats=b;
busPassengers=c;
}
//the abstract method
// needs to take in int b (standing seats)
public override double calculateOccupancy(int a, int c)
{
//this code calculates the leftover space in the vehicle
double busSpace=(busPassengers*100) / allSeats;
return busSpace;
//same code for the leftover standing space (int c)
}
}
}
class Person
{
protected string name;
protected string lastName;
//question 1
//properties for char gender
protected char gender;
//question 3
protected readonly string initials;
//the code errors, at the get/set
public char Gender
{
get{ return gender; }
set {gender=value;}
}
/*and the property im not sure how to make
public string Initials{}
*/
}
I hope the comments add some clarity, rather than confusion, thank you for your help everybody.
Assumption going forward - I threw some of your variable names into Google Translate and it seems to be Slovenian. I'm assuming that going forward which helped me make some clarity of what your code does.
1) Replace - If you already have a variable that is a char representing spol then I believe you're supposed to use the new enum type you are to create to represent it.
public enum Spol
{
Moski = 0,
Zenska = 1
}
Change:
protected char spol;
public char Spol
{
get{ return spol; }
set {spol=value;}
}
To: public Spol Spol { get; set; }
2) Defaults & Conditions - Use int c = 0 as your 3rd parameter and use a formula/algorithm that ignores it if it is the default value.
3) Getters - This property doesn't have a setter and therefore cannot be changed (directly).
public string GiveThisAName
{
get
{
if (String.IsNullOrWhiteSpace(ime))
{
return null;
}
if (String.IsNullOrWhiteSpace(priimek))
{
return null;
}
return ime[0] + '.' + priimek[0];
}
}
Notes
1) Heavily recommend making the parameters of your capacity function (i.e. izracunajZasedenost(int a, int b)) to be named something useful (i.e. a name descriptive of what they do) other than a and b.
2) For the record, #1 seems more like an appropriate question for your instructor, teacher, or whoever gave you this assignment.
Give the "optional" values a value when you create the abstract method
public abstract double izracunajZasedenost (int a = -1, int b = -1)
{
if (a == -1){
//do method with ignoring a
}
};

get set property usage

I am a bit confused with the get set property in C#.
I have the simple code below:
using System;
class Example
{
int _number;
public int Number
{
get
{
return this._number;
}
set
{
this._number = value;
}
}
}
class Program
{
static void Main()
{
Example example = new Example();
example.Number = 5; // set { }
Console.WriteLine(example.Number); // get { }
}
}
The code above using get set properties. However, if I delete the get set code like below code, the results stay the same.
using System;
class Example
{
int _number;
public int Number;
{
}
}
class Program
{
static void Main()
{
Example example = new Example();
example.Number = 5; // set { }
Console.WriteLine(example.Number); // get { }
}
}
My query is, what is the get set code used for? In the above program, the results are same. Can you give me some simple code which show the get set usage?
In your code, Number is simply a public field, as evidenced by the semicolon (;) at the end.
public int Number;
It is not a property, you just have an empty set of brackets right underneath which led to your confusion. If you were to remove the ; then you would actually have a property that is missing it's get, and would not compile at all.
All properties need to have a getter (setters are optional). If you want to avoid writing them, you can use auto properties, which take care of the backing field without you having to get involved:
public int Number { get; set; } // No field required
Note: A common usage pattern you'll see involving auto properties is the following:
public int Number { get; private set; }
This allows for properties that can be read from anywhere, but can only be modified from within the class they belong to.
EDIT: To answer your question, the main difference between fields and properties is in encapsulation. You can read more about the general differences between fields and properties here.
However, the example you have given has one additional difference, the private set. A normal field can be written from and to throughout the program. A property with a private setter however can only be modified from inside the class it belongs to.
Example:
public class Foo
{
public int Id { get; private set; }
public string Name;
public Foo()
{
this.Id = 1; // This works!
}
}
Here, Name is a field and Id is a property with a private setter. Notice that we modify Id in the constructor and that works, because it is within the class Id belongs to. Moving outside the class however:
var foo = new Foo();
// Field (no get and set):
foo.Name = "test" // Works
string bar = foo.Name; // Works
// Property (get and *private* set)
int i = foo.Id; // Works, because get is public
foo.Id = 2; // Doesn't work, because set is private

How to create an array of the same properties?

So pretty much, what I'm trying to do is create a properties grid. It will hold things like input 0-5 or like output 1-64, which will have sub-properties like name, id, etc. Right now my code is very straight forward, and I initialize each one individually. That caused a problem when I wanted to save them to a text file and realized that doing it that way will cause walls of code. Instead of just being able to do a for loop, I would have to grab each one individually to write to the text file. I was wondering if there was a better approach to doing this with an array or list.
Here is what I have right now:
[CategoryAttribute("Input 0"), DescriptionAttribute("Name of Input 0"), DisplayName("Input 0: Name")]
public string IName_0
{
get {return _Iname[0];}
set {_Iname[0] = value;}
}
[CategoryAttribute("Input 0"), DescriptionAttribute("ID of Input 0"), DisplayName("Input 0: ID")]
public int IID_0
{
get { return _IID[0]; }
set { if ((64 > value) && (value >= 0)) _IID[0] = value; }
}
[CategoryAttribute("Input 1"), DescriptionAttribute("Name of Input 1"), DisplayName("Input 1: Name")]
public string IName_1
{
get { return _Iname[1]; }
set { _Iname[1] = value; }
}
[CategoryAttribute("Input 1"), DescriptionAttribute("ID of Input 1"), DisplayName("Input 1: ID")]
public int IID_1
{
get { return _IID[1]; }
set { if ((64 > value) && (value >= 0)) _IID[1] = value; }
It goes on like that for each input. I have been looking everywhere, and I can't find a good fix.
First you have to realize that containing your properties in a collection will cause them to be grouped together under it, when displayed on your PropertyGrid.
Therefore, having a collection of strings and another of ints will break your current structure, of:
Having pairs of properties (name and ID) grouped together;
Having all the properties on the root level of the property grid.
Having said that, you could solve issue #1 by making #2 a bit worse.
create two classes:
MyClass - containing a Name and IID properties.
MyClassCollection - a container class (most likely using an underlying List).
To mitigate issue #2, you can add code to expand all nodes at initialization as shown here.
If you try this, you will notice that the "containers" (MyClassCollection and MyClass) will have some undesired decription text appearing next to them when displayed.
This is where this article comes in handy.
Your property would then be:
[DisplayName("Some info here"),
DescriptionAttribute("Some more descriptive info here...")]
virtual public MyClassCollection MyData { get; set; }
and your class definitions would be along the lines of:
public class MyClass
{
public string Name
{
get { return _name; }
set { _name = value; }
}
public int IID
{
get { return _iid; }
set { if ((64 > value) && (value >= 0)) _iid = value; }
}
private string _name;
private int _iid;
}
public class MyClassCollection : CollectionBase
{
// See the article for code for the overrides (for CollectionBase) and implementation (for ICustomTypeDescriptor)
}
If you look at the article mentioned above, regarding the tweaking of the display text of the container classes, you'll have to make some adjustments to the classes above.

Objects Retrieved from List<T> Appear to Be Copies, Not References

In my code, I have a class that maintains a number of lists. We'll focus on one of them for the moment, since it's the one that highlighted the problem.
internal List<Badge> Badges { get; private set; }
In the code, I add Badge instances to this list when an XML document is parsed. Later, I want to update the individual instances in the list so I can have the data written back out to XML. Because of the way the data's XML structure differs from the original file structure, there's some hocus-pocus involved, but that's largely mapped out. The surprise came when I attempted to update an item in the List<Badge>.
Specifically, the problematic code is here:
// Get the current badge from the loaded XML data, so we can update it.
var currentBadge = this.GameData.GetCurrentBadge();
I always get a valid badge back. The surprise, as I've come to find out, is that this simple test always fails:
var result = this.GameData.Badges.IndexOf(currentBadge);
result always evaluates to -1, indicating that the object doesn't exist in the collection. (EDIT: Updating the properties on currentBadge has no effect whatsoever on the contents of the matching item in this.GameData.Badges.) Which leads me to conclude that I'm getting a copy of my object back, and not a reference, as I would have expected.
For the inquisitive, the code to retrieve badges from the GameData class is included below. I have a sneaking suspicion that this is a documented behavior of generic lists, and that this is the first time I've stumbled across it. If so, I'm in for a very rude awakening. If it's not, I'd really like to know why my objects are coming back "disconnected" from their originals.
private Badge GetCurrentBadge()
{
var badgeItem = GetCurrentBadgeItem();
if (badgeItem != null)
{
return this.GameData.GetBadgeByText(badgeItem.Text);
}
return null;
}
private MenuOption GetCurrentBadgeItem()
{
if (!(this.currentItem is MenuOption &&
(this.currentItem as MenuOption).IsLocked))
{
return null;
}
MenuOption result = null;
var children = this.currentMenu.Children;
for (var n = children.Count - 1; n >= 0; n--)
{
var child = children[n] as MenuOption;
if (child == null || !child.IsLocked)
{
break;
}
if (!child.Text.StartsWith(" "))
{
result = child;
break;
}
}
return result;
}
UPDATE: Per request, GetBadgeByText, which comes from the GameData class.
internal Badge GetBadgeByText(string badgeText)
{
foreach (var badge in Badges)
{
if (badge.Text.ToLower() == badgeText.ToLower())
{
return badge;
}
}
return null;
// var b = (from l in Badges
// where l.Text.ToLower().StartsWith(badgeText.ToLower())
// select l).FirstOrDefault();
//return b;
}
As you can see, I've tried it both with and without Linq, just to eliminate that as the culprit. Changing the implementation had no noticable effect.
And for the record, all the objects in this application are CLASSES. No structs anywhere.
UPDATE #2: The Badge class.
internal class Badge
: GameDataItem
{
public Badge()
: base()
{
}
public string AuthId { get; set; }
public string Category { get; set; }
public string Description { get; set; }
public bool IsAccoladePower { get; set; }
public string RequiredBadges { get; set; }
public override string ToString()
{
return Text;
}
internal string ToXml()
{
var template = "<Badge value=\"{0}\" title=\"{1}\" category=\"{2}\" authid=\"{3}\" requires=\"{4}\" accolade=\"{5}\" description=\"{6}\" />";
return string.Format(template,
this.Value,
this.Text,
this.Category,
this.AuthId,
this.RequiredBadges,
this.IsAccoladePower,
this.Description);
}
}
And just in case someone asks for it, the base class:
internal class GameDataItem
{
private string _text;
public string Text
{
get
{
return this._text;
}
set
{
this._text = value.Replace("<", "<")
.Replace(">", ">")
.Replace("&", "&");
}
}
public string Value { get; set; }
public override string ToString()
{
return Text + "=\"" + Value + "\"";
}
}
Looks to me like this has something to do with MenuOption's implementation of Equals(object). The IndexOf() method of the List<> will use Equals(object) when deciding what to return.
Either:
You are putting a copy of the object in the list. (List<T> does not clone objects or do any other sort of trickery.)
Badge is a struct, not a class, which means that you don't actually hold references to it since it would be a value type.
There's some copying going on elsewhere in code you haven't pasted.
A generic List<T> does not copy objects. You add references to it, and the same references comes out - so there must be another problem in the code.
How is GetBadgeFromText implemented ? Does it read directly from the Badges List ?
Is this a web app ? If yes, does your List live between requests, or is it deserialized and serialized on each request (this could also be the problem).

Is it possible to bind complex type properties to a datagrid?

How would I go about binding the following object, Car, to a gridview?
public class Car
{
long Id {get; set;}
Manufacturer Maker {get; set;}
}
public class Manufacturer
{
long Id {get; set;}
String Name {get; set;}
}
The primitive types get bound easy but I have found no way of displaying anything for Maker. I would like for it to display the Manufacturer.Name. Is it even possible?
What would be a way to do it? Would I have to store ManufacturerId in Car as well and then setup an lookupEditRepository with list of Manufacturers?
Allright guys... This question was posted waaay back but I just found a fairly nice & simple way to do this by using reflection in the cell_formatting event to go retrieve the nested properties.
Goes like this:
private void Grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
DataGridView grid = (DataGridView)sender;
DataGridViewRow row = grid.Rows[e.RowIndex];
DataGridViewColumn col = grid.Columns[e.ColumnIndex];
if (row.DataBoundItem != null && col.DataPropertyName.Contains("."))
{
string[] props = col.DataPropertyName.Split('.');
PropertyInfo propInfo = row.DataBoundItem.GetType().GetProperty(props[0]);
object val = propInfo.GetValue(row.DataBoundItem, null);
for (int i = 1; i < props.Length; i++)
{
propInfo = val.GetType().GetProperty(props[i]);
val = propInfo.GetValue(val, null);
}
e.Value = val;
}
}
And that's it! You can now use the familiar syntax "ParentProp.ChildProp.GrandChildProp" in the DataPropertyName for your column.
Yes, you can create a TypeDescriptionProvider to accomplish nested binding. Here is a detailed example from an MSDN blog:
http://blogs.msdn.com/msdnts/archive/2007/01/19/how-to-bind-a-datagridview-column-to-a-second-level-property-of-a-data-source.aspx
The way that I approached this in a recent application was to create my own DataGridViewColumn and DataGridViewCell classes inheriting off of one of the existing ones such as DataGridViewTextBoxColumn and DataGridViewTextBoxCell.
Depending on the type of cell you want, you could use others such as Button, Checkbox, ComboBox, etc. Just take a look at the types available in System.Windows.Forms.
The cells deal with their value's as objects so you will be able to pass your Car class into the cell's value.
Overriding SetValue and GetValue will allow you to have any additional logic you need to handle the value.
For example:
public class CarCell : System.Windows.Forms.DataGridViewTextBoxCell
{
protected override object GetValue(int rowIndex)
{
Car car = base.GetValue(rowIndex) as Car;
if (car != null)
{
return car.Maker.Name;
}
else
{
return "";
}
}
}
On the column class the main thing you need to do is set the CellTemplate to your custom cell class.
public class CarColumn : System.Windows.Forms.DataGridViewTextBoxColumn
{
public CarColumn(): base()
{
CarCell c = new CarCell();
base.CellTemplate = c;
}
}
By using these custom Column/Cells on the DataGridView it allows you to add a lot of extra functionality to your DataGridView.
I used them to alter the displayed formatting by overriding GetFormattedValue to apply custom formatting to the string values.
I also did an override on Paint so that I could do custom cell highlighting depending on value conditions, altering the cells Style.BackColor to what I wanted based on the value.
public class Manufacturer
{
long Id {get; set;}
String Name {get; set;}
public override string ToString()
{
return Name;
}
}
Override the to string method.
Just use a List and set the DataMember to the string "Maker.Name" and if you want the DataKeyField to use car's ID just set that to "ID".
dataGrid.DataSource = carList;
dataGrid.DataMember = "Maker.Name";
dataGrid.DataKeyField = "ID";
dataGrid.DataBind();
I know that works in the repeater-control, at least...
If you want to expose specific, nested properties as binding targets, then Ben Hoffstein's answer (http://blogs.msdn.com/msdnts/archive/2007/01/19/how-to-bind-a-datagridview-column-to-a-second-level-property-of-a-data-source.aspx) is pretty good. The referenced article is a bit obtuse, but it works.
If you just want to bind a column to a complex property (e.g. Manufacturer) and override the rendering logic, then either do what ManiacXZ recommended, or just subclass BoundField and provide a custom implementation of FormatDataValue(). This is similar to overriding ToString(); you get an object reference, and you return the string you want displayed in your grid.
Something like this:
public class ManufacturerField : BoundField
{
protected override string FormatDataValue(object dataValue, bool encode)
{
var mfr = dataValue as Manufacturer;
if (mfr != null)
{
return mfr.Name + " (ID " + mfr.Id + ")";
}
else
{
return base.FormatDataValue(dataValue, encode);
}
}
}
Just add a ManufacturerField to your grid, specifying "Manufacturer" as the data field, and you're good to go.
Here's another option I got working:
<asp:TemplateColumn
HeaderText="Maker">
<ItemTemplate>
<%#Eval("Maker.Name")%>
</ItemTemplate>
</asp:TemplateColumn>
Might be ASP.NET 4.0 specific but it works like a charm!
I would assume you could do the following:
public class Car
{
public long Id {get; set;}
public Manufacturer Maker {private get; set;}
public string ManufacturerName
{
get { return Maker != null ? Maker.Name : ""; }
}
}
public class Manufacturer
{
long Id {get; set;}
String Name {get; set;}
}

Categories

Resources