C# Form is displaying an extra object - c#

So I have a parent class called SalesRep and a child class called SeniorSalesRep. I have got it so it displays both classes polymorphically to a listbox. The issue I'm having is that I have a combo box that gives the user the choice of displaying a report of the objects in the SalesRep class which should also display the SeniorSalesRep objects and if it's selected just SeniorSalesRep it only shows SeniorSales Rep objects. However, when I'm implementing this it creates an extra object called object which displays only SalesRepObjects and not SeniorSalesRep objects. How can I get rid of that extra object in my combo box?
public void LoadTypeComboBox()
{
List<string> salesRepTypes = new List<string>();
foreach (SalesRep thisSalesRep in allSalesReps)
{
string s = thisSalesRep.GetType().Name;
string baseType = thisSalesRep.GetType().BaseType.Name;
if (!salesRepTypes.Contains(s))
{
salesRepTypes.Add(s);
}
if (!salesRepTypes.Contains(baseType))
{
salesRepTypes.Add(baseType);
}
}
cboObjectType.DataSource = salesRepTypes;
}
private void cboObjectType_SelectedIndexChanged(object sender, EventArgs e)
{
lstSalesReps.DataSource = null;
lstSalesReps.Items.Clear();
foreach (var i in allSalesReps)
{
if (i.GetType().Name == cboObjectType.SelectedItem.ToString())
{
lstSalesReps.Items.Add(i);
}
else if (i.GetType().BaseType.Name == cboObjectType.SelectedItem.ToString())
{
lstSalesReps.Items.Add(i);
}
}
}
Form Output

The code that shows object in combobox is this:
string baseType = thisSalesRep.GetType().BaseType.Name;
The base type of SalesRep is object. You should either remove object from your collection or never add in the first place.
GetType gives you the runtime type of the object. So I don't think you need .BaseType. Try this:
public void LoadTypeComboBox()
{
List<string> salesRepTypes = new List<string>();
foreach (SalesRep thisSalesRep in allSalesReps)
{
string type = thisSalesRep.GetType().Name;
if (!salesRepTypes.Contains(s))
{
salesRepTypes.Add(s);
}
}
cboObjectType.DataSource = salesRepTypes;
}
Or even better with Linq:
cboObjectType.DataSource = allSalesReps
.Select(r => r.GetType().Name)
.Distinct()
.ToList();

Related

How to fill private member List<string> in OOP

I want to add all of the items from a listbox inside of a list. This list is a string-list and a part of the private members from my object "Deur".
When i try to loop over the listbox listitems and add them inside this list, i get an error saying "System.NullReferenceException: 'Object reference not set to an instance of an object.'"
I've tried to Convert the "Listbox.Text" item to a string (which it alredy is), but that didn't help.
Here is the code where i try to add it to my list:
LBSupplementen is the ListBox, b.SupplementenLijst is the List.
if (LBSupplementen.Items.Count > 0)
foreach (ListItem i in LBSupplementen.Items)
b.SupplementLijst.Add(Convert.ToString(i.Text));
and here is where i define my List in my object class "Deur":
private List<string> _SupplementLijst;
public Deur()
{
_GaasID = GaasID;
_Gaas = Gaas;
_ProductID = ProductID;
_Product = Product;
_Hoogte = Hoogte;
_Breedte = Breedte;
_KleurID = KLeurID;
_Kleur = Kleur;
_SupplementLijst = SupplementLijst;
_SupplementLijstID = SupplementLijstID;
_Prijs = Prijs;
}
public List<string> SupplementLijst
{
get { return _SupplementLijst; }
set { _SupplementLijst = value; }
}
Have you instantiated the list in your "Deur" class? If not, make sure you instantiate your list in the constructor like this:
private List<string> MyList;
public Deur()
{
MyList = new List<string>(); // Add this here
}
If you want your list to stay private, add a method to your "Deur" class that you can use to put items in your list from outside, like this:
public void AddToList(string item)
{
MyList.Add(item);
}

Casting mistake

Currently, in course, I am trying to check the LandCode from the class Landen to get the cities from the selectedItem land, but I am parsing something wrong.
public partial class Landen
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Landen()
{
this.Steden = new HashSet<Steden>();
this.Talen = new HashSet<Talen>();
}
public string LandCode { get; set; }
public string Naam { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Steden> Steden { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Talen> Talen { get; set; }
}
public MainWindow()
{
InitializeComponent();
var context = new LandenStedenTalenEntities();
landenListBox.ItemsSource = (from Landen in context.Landen select Landen.Naam).ToList();
}
private void landenListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
using (var entities = new LandenStedenTalenEntities())
{
List<string> steden = new List<string>();
var landcode = ((Landen)landenListBox.SelectedItem).LandCode.ToString();
var gekozenland = entities.Landen.Find(landcode);
foreach(var stad in gekozenland.Steden)
{
steden.Add(stad.Naam);
}
stedenInLandenListBox.ItemsSource = steden.ToList();
}
}
Exception:
Unable to cast object of type 'System.String' to type 'TestEFDieter.Landen'.
I want to add them to a list and show them in a second Listbox.
Can anyone help me out? Thank you.
I would suggest you modify the code inside of the constructor so that the landenListBox will contain actual Landen object and displays only the Naam as it's item.
Change the code in the constructor to this:
public MainWindow()
{
InitializeComponent();
var context = new LandenStedenTalenEntities();
landenListBox.ItemsSource = context.Landen.ToList();
landenListBox.DisplayMemberPath = "Naam";
}
Adding DisplayMemberPath will inform ListBox to display that particular property as an item instead of calling ToString() method on that object.
Now in your later code you do not have to change much, just remove ToList() and since you're using EntityFramework you should insert the whole model in it's Find() method but it's useless since you already have that object loaded. You can just retrieve stad from it directly and display it in the same way Landen is displayed:
private void landenListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var landen = landenListBox.SelectedItem as Landen; // safe cast just in case
if (landen != null && landen.Steden != null ) // null checks
{
stedenInLandenListBox.ItemsSource = landen.Steden.ToList(); // in case it's proxy object
stadenInLandenListBox.DisplayMemberPath = "Naam";
}
}
I suppose you want to get that instance of Landen which corresponds the selected item in your list. As the elements in the listbox are just strings that represent the Naam-property of every Landen, you could simply iterate your list of Landen and get that one with the desired Naam:
var selectedLanden = landenList.FirstOrDefault(x => x.Naam == landenListBox.SelectedItem);
if(selectedLanden != null)
{
var landCode = selectedLanden.LandCode;
// ...
}
However as selectedLanden already is an instance of Landen, you won´t need to find it again by its LandCode. Thus your code boils donw to this:
List<string> steden = new List<string>();
var selectedLanden = landenList.FirstOrDefault(x => x.Naam == landenListBox.SelectedItem);
if(selectedLanden != null)
{
foreach(var stad in selectedLanden.Steden)
{
steden.Add(stad.Naam);
}
}
stedenInLandenListBox.ItemsSource = steden.ToList();
or a bit shorter:
stedenInLandenListBox.ItemsSource = selectedLanden.SelectMany(x => x.Steden.Select(y => y.Naam)).ToList();
For this to work you of course have to store a reference to the list of Landen somewehere in your class:
class MainWindow
{
List<Landen> landenList;
public MainWindow()
{
InitializeComponent();
this.landenList = new LandenStedenTalenEntities();
landenListBox.ItemsSource = (from Landen in this.landenList select Landen.Naam).ToList();
}
}

Object Reference not set when using PrinterSettings.StringCollection

I am attempting to list the currently installed printers using PrinterSettings.StringCollection. However, I get this error:
Object Reference not set to an instance of an object
Code is as follows:
namespace DropDownLibrary
{
public class DropDownExample : DSDropDownBase
{
public DropDownExample() : base("item") { }
public static PrinterSettings.StringCollection InstalledPrinters { get; }
public override void PopulateItems()
{
// The Items collection contains the elements
// that appear in the list.
Items.Clear();
// Create a number of DynamoDropDownItem objects
// to store the items that we want to appear in our list.
var newItems = new List<DynamoDropDownItem>();
{
foreach (String name in InstalledPrinters)
{
new DynamoDropDownItem("{0}", name);
}
};
Items.AddRange(newItems);
// Set the selected index to something other
// than -1, the default, so that your list
// has a pre-selection.
SelectedIndex = 0;
}
public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
{
// Build an AST node for the type of object contained in your Items collection.
var intNode = AstFactory.BuildIntNode((int)Items[SelectedIndex].Item);
var assign = AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), intNode);
return new List<AssociativeNode> { assign };
}
}
}
This is covered in this post. The 'Object reference not set to instance of an Object" error is caused by you trying to use a variable that is null. For instance, you can get a null reference error by doing:
object nullObject = null;
nullObject.ToString():
In your code, it doesn't look like the value for InstalledPrinters ever gets set.
Before your code reaches this line:
foreach (String name in InstalledPrinters)
It looks like you copy pasted this from this link:
public static PrinterSettings.StringCollection InstalledPrinters { get; }
This is a property on the PrinterSettings class that you can access. You should access it like so:
var installedPrinters = System.Drawing.Printing.PrinterSettings.InstalledPrinters;
foreach (String name in installedPrinters)

difficulty inserting a name to an inserted object of a checkedlistbox

I am abit new in C# and i am trying to insert an object to a CheckedListBox,
so this inserted item will have a title inside the checked list (my object contains a string field inside it which I want to be displayed in the CheckedListBox).
for example this is my class:
public class InfoLayer
{
private string LayerName;
private List<GeoInfo> GeoInfos;
public InfoLayer()
{
LayerName = "New Empty Layer";
GeoInfos = new List<GeoInfo>();
}
public InfoLayer(string LayerName)
{
this.LayerName = LayerName;
GeoInfos = new List<GeoInfo>();
}
public InfoLayer(string LayerName,List<GeoInfo> GeoInfosToClone):this(LayerName)
{
foreach (GeoInfo item in GeoInfosToClone)
{
GeoInfos.Add((GeoInfo)((ICloneable)item).Clone());
}
}
public GeoInfo SearchElement(long id)
{
foreach (GeoInfo info in GeoInfos) // foreach loop running on the list
{
if (info.INFOID == id)
return info; // return the item if we found it
}
return null;
}
public GeoInfo SearchElement(string name)
{
foreach (GeoInfo info in GeoInfos)
{
if (info.INFONAME.CompareTo(name)==0)
return info;
}
return null;
}
public override string ToString()
{
string toReturn = "";
for (int i = 0; i < GeoInfos.Count; i++) // for loop running on the list
{
toReturn += String.Format("{0}\n",GeoInfos[i].ToString()); // piping another geoinfo
}
return toReturn;
}
public string LAYERNAME{get{return LayerName;}}
my class also contains a tostring overrider inside her (not what i want to display)
thanks in advance for your help.
Override ToString() in your class, the class that the object is an instance of.
Edit:
You don't want to display the contents of ToString(). You want to display the LayerName, don't you? Perhaps you should display the values with Databinding instead. Then you can set DisplayMember to your new LAYERNAME property.
I believe this is what you are trying to achieve:
checkedListBox1.Items.Add(yourObject.stringField);
((MyObjectType)checkedListBox1.Items(index)).Name = "whatever"
You will have to know the index of the object you want to change.
You'll just have to override the ToString method in your class so that it returns this Name property value.
public overrides string ToString() {
return Name;
}
It will then display its name when added to your CheckedListbox.

Adding Items to ListBox, RadioList, Combobox using reflection

I'm trying to add items to a listbox,combobox, radiolist using reflection. The code I have at the moment is as follows:
public static Control ConfigureControl(Control control, ControlConfig ctrlconf)
{
if (control is TextBox)
{
// ...
}
else
{
// get the properties of the control
//
Type controlType = control.GetType();
PropertyInfo[] controlPropertiesArray = controlType.GetProperties();
foreach (PropertyInfo controlProperty in controlPropertiesArray)
{
if (controlProperty.Name == "Items" && controlProperty.PropertyType == typeof(ListItemCollection))
{
object instance = Activator.CreateInstance(controlProperty.PropertyType);
MethodInfo addMethod = controlProperty.PropertyType.GetMethod("Add", new Type[] { typeof(ListItem)} );
List<string> popValues = new List<string>(ctrlconf.PopulatedValues.Split(';'));
if (popValues.Count.Equals(0))
{
throw new ArgumentException("No values found for control");
}
else
{
foreach (string val in popValues)
{
addMethod.Invoke(instance, new object[] { new ListItem(val, val) });
}
}
}
}
}
return control;
}
The code above populates the listitemcollection which I have instantiated using Activator.CreateInstance, however I'm not sure how to add it to the ListBox.
Any help would be great.
Thanks,
Peter
You don't need or want to instantiate the collection object: that's already done by the control. Instead, you need to get the existing collection object, then add to that:
if (controlProperty.Name == "Items" && controlProperty.PropertyType == typeof(ListItemCollection))
{
object instance = controlProperty.GetValue(control, null);
// ... now go on and add to the collection ...
}
However, as others have noted, this may not be the best way to approach the problem. Instead, consider implementing adapter or strategy for the various controls you want to support e.g. RadioButtonListItemAdder, ListControlItemAdder, etc., which all conform to a common interface. Each type of XxxItemAdder can implement its own strongly-typed code, suitable for the type of control it's responsible for adding items to. This might look something like the following:
public interface IItemAdder
{
void AddItem(string value);
}
public class ListControlItemAdder : IItemAdder
{
private readonly ListControl _listControl;
public ListControlItemAdder(ListControl listControl)
{
_listControl = listControl;
}
public void AddItem(string value)
{
_listControl.Items.Add(value); // or new ListItem(value, value) per your original code
}
}
public class RadioButtonListItemAdder : IItemAdder
{
// ...
public void AddItem(string value)
{
// do whatever you have to do to add an item to a list of RadioButtons
}
}
public static IItemAdder CreateItemAdderFor(Control control)
{
if (control is ListControl)
return new ListControlItemAdder((ListControl)control);
else if (control is RadioButtonList)
return new RadioButtonListItemAdder((RadioButtonList)control);
// etc. to cover other cases
}
public static Control ConfigureControl(Control control, ...)
{
// ... omitting code that looks like your existing code ...
IItemAdder itemAdder = CreateItemAdderFor(control);
foreach (string val in popValues)
itemAdder.AddItem(val);
}
This is a really untidy implementation but hopefully gives you the idea of how you can separate out each of the individual control-specific implementations into small, nicely separated classes.

Categories