I have the following code
clbCodes.DisplayMember = "Name";
clbCodes.ValueMember = "Id";
checkboxItemList = new List<CheckBoxItem>();
foreach (var uagCode in codes)
{
var checkboxItem = new CheckBoxItem
{
Id = uagCode.Code,
Name = uagCode.UAGLabel
};
checkboxItemList.Add(checkboxItem);
}
clbCodes.DataSource = checkboxItemList;
public class CheckBoxItem
{
public string Name { get; set; }
public string Id { get; set; }
}
However, when I run this, instead of seeing the "Name" of my item, e.g.,
"Card"
"Toy"
"Table"
I see
WindowsApplication1.CheckBoxItem
WindowsApplication1.CheckBoxItem
WindowsApplication1.CheckBoxItem
populated in my listbox
What did I do wrong?
Since it appears that you are adding to the CheckListBox a collection of custom objects, you should have as part of that class an override of ToString() that can return the Name that you are wanting to display.
public override String ToString()
{
return this.Name;
}
You need to override ToString:
public class CheckBoxItem
{
public string Name { get; set; }
public string Id { get; set; }
public override String ToString()
{
return Name;
}
}
Related
I am writing a method for extracting all properties from an object (including properties of its own) with custom attribute . For example
public class SomeModel
{
[Custom]
public string Name { get; set; }
public string TestData { get; set; }
[Custom]
public string Surname { get; set; }
public InnerModel InnerModel { get; set; }
}
And Inner Model :
public class InnerModel
{
public string Id { get; set; } = "TestID";
[Custom]
public string Year { get; set; }
public ThirdObject HidedObject { get; set; }
}
And the third one :
public class ThirdObject
{
[Custom]
public string HidedName { get; set; }
}
I need to find all properties with "Custom" attribute .
Testing :
SomeModel model = new SomeModel()
{
Name = "farid",
Surname = "Ismayilzada",
TestData = "Test" ,
InnerModel = new InnerModel() { Year ="2022" , HidedObject= New ThirdObject{ HidedName="Secret"}}
};
I need to write the method
GetMyProperties(model) => List<PropInf>()
[PropertyName= Name,Value=Farid ,Route="Name" ]
[PropertyName= Surname,Value=Ismayilzada,Route="Surname" ]
[PropertyName= Year,Value=2022,Route="InnerModel.Year" ]
[PropertyName= HidedName,Value=Secret,Route="InnerModel.HidedObject.HidedName" ]
How to get this information ?
You can write a method like this :
private static IEnumerable<PropInfo> GetPropertiesInfo(object obj, string route = "")
{
List<PropInfo> results = new List<PropInfo>();
// You can filter wich property you want https://learn.microsoft.com/en-us/dotnet/api/system.reflection.propertyinfo?view=net-6.0
var objectProperties = obj.GetType().GetProperties().Where(p => p.CanRead);
foreach (var property in objectProperties)
{
var value = property.GetValue(obj);
if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
{
results.AddRange(GetPropertiesInfo(value, route + property.Name + "."));
}
else
{
// Check if the property has the Custom Attribute
var customAttributes = property.GetCustomAttributes<CustomAttribute>();
if (!customAttributes.Any())
continue;
// You can set a method in your Attribute : customAttributes.First().CheckIfNeedToStoreProperty(obj);
results.Add(new PropInfo()
{
PropertyName = property.Name,
Value = value,
Route = route + property.Name
});
}
}
return results;
}
public class PropInfo
{
public string PropertyName { get; set; }
public object Value { get; set; }
public string Route { get; set; }
}
public class CustomAttribute : Attribute
{
public bool CheckIfNeedToStoreProperty(object obj)
{
return true;
}
}
The propblem: There is no "Name" field in the object or csv file, yet CsVHelper keeps looking for "Name" in the header. So why is it tripping there and what are some fixes?
When trying to build objects from a csv file, the following error comes up:
CsvHelper.HeaderValidationException: Header with name 'Name' was not found. If you are expecting some headers to be missing and want to ignore this validation, set the configuration HeaderValidated to null. You can also change the functionality to do something else, like logging the issue.
at CsvHelper.Configuration.ConfigurationFunctions.HeaderValidated(Boolean isValid, String[] headerNames, Int32 headerNameIndex, ReadingContext context)
I have tried setting HeaderValidated to null, but got the same results.
The header of the csv:
Id|Title|Description|AssignedToUserId|SourceUserId|DateCreated|DateAssigned|DateCompleted|Notes
The parsing code:
private static IEnumerable<T> GetCSVData<T>(string fullFileName)
{
PrintMembers<T>();
using (var reader = new StreamReader(fullFileName))
{
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = true;
csv.Configuration.IncludePrivateMembers = false;
csv.Parser.Configuration.Delimiter = "|";
var records = csv.GetRecords<T>().ToList();
return records;
}
}
}
A quick function for listing the public properties and fields of the class (T) being passed in outputs the following:
Properties...
Id
AssignedToUserId
SourceUserId
Title
Description
AssignedTo
Source
DateCreated
DateAssigned
DateCompleted
RelatedTasks
Notes
Fields...
[None]
They all have getters and setters.
EDIT
The IntermediateTask is the generic being fed into GetCSVData(). It has a default constructor. IntermediateTask is internal, but is in the same assembly as GetCSVData().
Code for the class(es) in question:
internal class IntermediateTask : Task
{
private int _Id;
new public int Id
{
get { return _Id; }
set { _Id = value; }
}
private int _AssignedToUserId;
public int AssignedToUserId
{
get { return _AssignedToUserId; }
set
{
_AssignedToUserId = value;
base.AssignedTo = userManager.Get(_AssignedToUserId);
}
}
private int _SourceUserId;
public int SourceUserId
{
get { return _SourceUserId; }
set
{
this._SourceUserId = value;
base.Source = userManager.Get(_SourceUserId);
}
}
public IntermediateTask() : base("", "", new IntermediateUser(), new IntermediateUser())
{
}
}
public class Task
{
public Task(string title, string description, User assignedTo, User source, DateTime? dateCreated = null, int id = 0)
{
this.RelatedTasks = new List<Task>();
this.Title = title;
this.Description = description;
this.AssignedTo = assignedTo;
this.Source = source;
this.DateCreated = dateCreated ?? DateTime.Now;
this.Id = id;
}
private int _Id;
public int Id
{
get { return _Id; }
protected set { _Id = value; }
}
public string Title { get; set; }
public string Description { get; set; }
public User AssignedTo { get; set; }
public User Source { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateAssigned { get; set; }
public DateTime? DateCompleted { get; set; }
public IList<Task> RelatedTasks { get; set; }
public string Notes { get; set; }
override public string ToString()
{
return $"Id: {Id}; Title: {Title}";
}
}
In my case it complained about AssignedTo missing, but that is actually a property in the class that is not in the csv, so I had to add these two lines to make it work:
csv.Configuration.HeaderValidated = null;
csv.Configuration.MissingFieldFound = null;
I don't know why it would come up with 'Name' unless you have something different.
I have this method that adds Conta instances to a ComboBox called "comboContas":
public void AdicionaConta(Conta novaConta)
{
comboContas.Items.Add(novaConta);
comboContas.DisplayMember = "Titular";
}
Note that I've set the DisplayMember property to "Titular". Here is my Conta class:
public abstract class Conta
{
public int Numero { get; set; }
public double Saldo { get; set; }
public Cliente Titular { get; set; }
public override string ToString()
{
return "titular: " + this.Titular.Nome;
}
}
Now, "Titular" is of Cliente type.
Here's Cliente class:
public class Cliente
{
public string Nome { get; set; }
public string Rg { get; set; }
public Cliente(string nome)
{
this.Nome = nome;
}
public override string ToString()
{
return "ToString do Cliente: " + this.Nome;
}
}
What I'd like to show in the "comboContas" ComboBox is something like "ToString do Cliente: Gabriel".
However, the ToString method of the Cliente class is not being called. Instead, the one being called is from the Conta class.
This is pretty simple stuff and I really don't know what's happening. If I change DisplayMember to any other property, it works. If I change the type of the "Titular" property to any other type, the ToString() of this other type is called. It just doesn't work with Cliente.
Something is wrong with your code (setting it after every add instead of in advance?) because it indeed works as expected. Check it out:
using System;
using System.Windows.Forms;
namespace Tests
{
public class Conta
{
public int Numero { get; set; }
public double Saldo { get; set; }
public Cliente Titular { get; set; }
public override string ToString()
{
return "titular: " + this.Titular.Nome;
}
}
public class Cliente
{
public string Nome { get; set; }
public string Rg { get; set; }
public Cliente(string nome)
{
this.Nome = nome;
}
public override string ToString()
{
return "ToString do Cliente: " + this.Nome;
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new Form { Padding = new Padding(16) };
var comboBox = new ComboBox { Dock = DockStyle.Top, Parent = form };
comboBox.DisplayMember = "Titular";
comboBox.Items.AddRange( new []
{
new Conta { Titular = new Cliente("Victor") },
new Conta { Titular = new Cliente("Mauricio") },
new Conta { Titular = new Cliente("csni") },
});
Application.Run(form);
}
}
}
Result:
I'm not 100% sure why what you are doing isn't working, but one way that would likely work is to do something like this:
public class Client
{
public string DisplayName { get { return "ToString do Client: " + this.Nome; } }
}
Then, just change your combo box to bind the DisplayMember to DisplayName:
public void AdicionaConta(Conta novaConta)
{
comboContas.Items.Add(novaConta);
comboContas.DisplayMember = "Titular.DisplayName";
}
I hope this helps!
I know I can use reflection to set a objects property like this below.
public void SaveContent(string propertyName, string contentToUpdate, string corePageId)
{
var page = Session.Load<CorePage>(corePageId);
Type type = page.GetType();
PropertyInfo prop = type.GetProperty(propertyName);
prop.SetValue(page, contentToUpdate, null);
}
I'm having these classes below:
public class CorePage
{
public string BigHeader { get; set; }
public List<BigLinks> BigLinks { get; set; }
}
public class BigLinks
{
public string TextContent { get; set; }
}
My SaveContent()-method works obviously when the property to set is, for example public string BigHeader { get; set; }
But how can I do this if the the property I want to set is in the property:
public List<BigLinks> BigLinks { get; set; }
If public List<BigLinks> BigLinks { get; set; } is a list of 5 BigLinks objects, how can a set the value of, for example the third objects public string TextContent { get; set; }?
You have to get the property value using reflection and change the desired value like this:
var c = new CorePage() { BigLinks = new List<BigLinks> { new BigLinks { TextContent = "Y"}}};
var r = typeof(CorePage).GetProperty("BigLinks").GetGetMethod().Invoke(c, null) as List<BigLinks>;
r[0].TextContent = "X";
If you don't know the type of list item:
var itemInList = (typeof(CorePage).GetProperty("BigLinks").GetGetMethod().Invoke(c, null) as IList)[0];
itemInList.GetType().GetProperty("TextContent").SetValue(itemInList, "XXX", null);
Another option is casting to dynamic:
var itemInList = (typeof(CorePage).GetProperty("BigLinks").GetGetMethod().Invoke(c, null) as dynamic)[0].TextContent = "XXXTTT";
In my controller I'm looping through items and saving them to my db. The problem is that it saves the first item, but none of the others. I put a breakpoint on the "SaveItem()" line in the loop and it hits it every time, but what seems odd to me is that it only goes through to the method for the 1st item.
What am I doing wrong?
public void SubmitItem(Cart cart, ShippingDetails shippingDetails, ProcessedItems processedItem, string orderID)
{
var cartItems = cart.Lines;
//CartIndexViewModel cartIndex = new CartIndexViewModel();
//var customID = cartIndex.OrderID;
foreach(var item in cartItems)
{
processedItem.OrderID = orderID;
processedItem.ProductID = item.Product.ProductID;
processedItem.Name = item.Product.Name;
processedItem.Description = item.Product.Description;
processedItem.Price = item.Product.Price;
processedItem.Category = item.Product.Category;
processedItem.ImageName = item.Product.ImageName;
processedItem.Image2Name = item.Product.Image2Name;
processedItem.Image3Name = item.Product.Image3Name;
processedItem.BuyerName = shippingDetails.Name;
processedItem.Line1 = shippingDetails.Line1;
processedItem.Line2 = shippingDetails.Line2;
processedItem.Line3 = shippingDetails.Line3;
processedItem.City = shippingDetails.City;
processedItem.State = shippingDetails.State;
processedItem.Zip = shippingDetails.Zip;
processedItem.Country = shippingDetails.Country;
processedItem.Status = "Submitted";
processedItems.SaveItem(processedItem);
}
}
public class EFProcessedItemsRepository : IProcessedItems
{
private EFDbContext context = new EFDbContext();
public IQueryable<ProcessedItems> ProcessedItem
{
get { return context.ProcessedItems; }
}
public void SaveItem(ProcessedItems processedItem)
{
if(processedItem.ProcessedID == 0)
{
try
{
context.ProcessedItems.Add(processedItem);
context.SaveChanges();
}
catch (Exception)
{
throw;
}
}
else
{
context.Entry(processedItem).State = EntityState.Modified;
}
}
public void DeleteItem(ProcessedItems processedItem)
{
context.ProcessedItems.Remove(processedItem);
context.SaveChanges();
}
}
here is the class for the processedItem:
public class ProcessedItems
{
[Key]
public int ProcessedID { get; set; }
public string OrderID { get; set; }
public int ProductID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
public string ImageName { get; set; }
public string Image2Name { get; set; }
public string Image3Name { get; set; }
public string Status { get; set; }
//shipping
public string BuyerName { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Country { get; set; }
}
Interface:
public interface IProcessedItems
{
IQueryable<ProcessedItems> ProcessedItem { get; }
void SaveItem(ProcessedItems processedItem);
void DeleteItem(ProcessedItems processedItem);
}
try calling context.SaveChanges() after adding all of the items, I think it should persist them all in one go.
Another thing to try:
Refactor your code so that SaveItem accepts only one item to save, Add it and call SaveChanges()
Loop through the cart items outside the method and call the method with one item to save at a time.
// set orderID, shippingDetails above
foreach(var item in cartItems)
{
ProcessedItems processedItem = new ProcessedItems();
processedItem.OrderID = orderID;
processedItem.ProductID = item.Product.ProductID;
processedItem.Name = item.Product.Name;
processedItem.Description = item.Product.Description;
processedItem.Price = item.Product.Price;
processedItem.Category = item.Product.Category;
processedItem.ImageName = item.Product.ImageName;
processedItem.Image2Name = item.Product.Image2Name;
processedItem.Image3Name = item.Product.Image3Name;
processedItem.BuyerName = shippingDetails.Name;
processedItem.Line1 = shippingDetails.Line1;
processedItem.Line2 = shippingDetails.Line2;
processedItem.Line3 = shippingDetails.Line3;
processedItem.City = shippingDetails.City;
processedItem.State = shippingDetails.State;
processedItem.Zip = shippingDetails.Zip;
processedItem.Country = shippingDetails.Country;
SubmitItem(processedItem);
}
public void SubmitItem(ProcessedItems processedItem)
{
processedItem.Status = "Submitted";
processedItems.SaveItem(processedItem);
}
I think it is because processedItem is the same instance for each loop iteration. So after it has been through SaveItem once, it has its ProcessedID set and therefore won't get processed again.
My first guess is that you always store one entity, which is stored in processedItem, which is a input parameter. Try to create new Entity on each loop and then save it. In other words, you assign values to input parameter
processedItem.OrderID = orderID;
and then store same entity each time, but with changed fields
processedItems.SaveItem(processedItem);