I have a data structure as follows:
public class BranchLevel_1
{
public string Name { get; set; }
public ObservableCollection<BranchLevel_2> Children { get; set; }
public BranchLevel_1(string name, List<BranchLevel_2> children)
{
this.Name = name;
this.Children = new ObservableCollection<BranchLevel_2>(children);
}
}
public class BranchLevel_2
{
public ObservableCollection<BranchLevel_3> Contents { get; set; }
public BranchLevel_2(List<string> contents)
{
this.Contents = new ObservableCollection<BranchLevel_3>();
for (int i = 0; i < contents.Count; i++)
{
this.Contents.Add(new BranchLevel_3(contents[i]));
}
}
}
public class BranchLevel_3
{
public string Content { get; set; }
public BranchLevel_3(string text)
{
this.Content = text;
}
}
Sorting data on the first level is easy and I can obtain in easily by:
Level1_Data.OrderBy(item => item.Name).ToList()
However, I am stuck with sorting on the second level. BranchLevel_2 class is just a container for items stored in BranchLevel_3 classes. Therefore I would like to sort Level2 with data stored in BranchLevel_2.Contents1.Content value. This syntax for me seems to be correct and I cannot locate the problem...
Level1_Data.Select(item_Level1 => item_Level1.Children.OrderBy(item_Level2 => item_Level2.Contents[1].Content)).ToList();
Any hints?
Here is the rusult (indicated in yellow is supposed to be sorted alphabetically)
Why not just sort the contents before adding them to the ObservableCollection
public class BranchLevel_2
{
public ObservableCollection<BranchLevel_3> Contents { get; set; }
public BranchLevel_2(List<string> contents)
{
this.Contents = new ObservableCollection<BranchLevel_3>();
foreach (var content in contents.OrderBy(c => c))
{
this.Contents.Add(new BranchLevel_3(content));
}
}
}
Here is a solution that solved the problem, thanks to suggestion from #bhmahler
public class BranchLevel_1
{
public string Name { get; set; }
public ObservableCollection<BranchLevel_2> Children { get; set; }
public BranchLevel_1(string name, List<BranchLevel_2> children)
{
this.Name = name;
//this line needs to be added before creating ObservableCollection
children.OrderBy(item_level2 => item_level2.Contents[1].Content).ToList();
this.Children = new ObservableCollection<BranchLevel_2>(children);
}
}
Related
I would like to map the data from one list of objects and another. I am looping through CompanyAEmployee list and able to map FullName and Title. But not able to map Children property.
public class CompanyAEmployee
{
public string FullName { get; set; }
public string Title { get; set; }
public List<CompanyAEmployee> Children { get; set; }
}
public class CompanyBEmployee
{
public string Name { get; set; }
public string PositionName { get; set; }
public List<CompanyBEmployee> Children { get; set; }
}
companyAEmployeeList; // stores all employees of companyA
var companyBEmployeeList = new List<CompanyBEmployee>();
foreach(var employee in companyAEmployeeList)
{
var companyBEmployee = new CompanyBEmployee();
companyBEmployee.Name = employee.FullName;
companyBEmployee.PositionName = employee.Title;
//how to map the children??
}
Can someone suggest a way to map Children?
You can create a recusive method, like below:
public CompanyBEmployee ComAToComB(CompanyAEmployee a){
CompanyBEmployee b = new(){
Name = a.FullName,
PositionName = a.Title,
Children = new()
};
foreach(var child in a.Children){
b.Children.Add(ComAToComB(child));
}
return b;
}
And then call it like
var comB = ComAToComB(comA);
So, in my case it was best solution to use extension methods.
You can see example here
https://dotnetfiddle.net/SwhGMY
Main idea is to use such extension method that was called recursively.
public static class ClassConverterExtensions
{
public static CompanyBEmployee ToCompanyBEmployee(this CompanyAEmployee that)
{
var result = new CompanyBEmployee();
result.Name = that.FullName;
result.PositionName = that.Title;
if(that.Children == null)
{
return result;
}
result.Children = new List<CompanyBEmployee>();
foreach(var item in that.Children)
{
result.Children.Add(item.ToCompanyBEmployee());
}
return result;
}
}
Good point is that you can write this without changing source code of classes CompanyBEmployee and CompanyAEmployee
So, this classes is not referenced one to another, but you can write converters From A to B and from B to A without cyclic references.
Here is the solution:
public class CompanyAEmployee
{
public string FullName { get; set; }
public string Title { get; set; }
public List<CompanyAEmployee> Children { get; set; }
public static explicit operator CompanyBEmployee(CompanyAEmployee employee)
{
CompanyBEmployee employee1 = new CompanyBEmployee();
employee1.Name = employee.FullName;
employee1.PositionName = employee.Title;
employee1.Children = new List<CompanyBEmployee>(employee.Children.Count);
int count = employee.Children.Count;
for (int i = 0; i < count; i++)
employee1.Children[i] = (CompanyBEmployee)employee.Children[i];
return employee1;
}
}
public class CompanyBEmployee
{
public string Name { get; set; }
public string PositionName { get; set; }
public List<CompanyBEmployee> Children { get; set; }
}
Now you can just use an assignment operator with explicit casting from CompanyAEmployee to CompanyBEmployee.
Like this:
CompanyAEmployee employee = new CompanyAEmployee();
//... assign all the fields
CompanyBEmployee employee2 = (CompanyBEmployee)employee.
Now you are done!
This is a continuation of another post. I'm trying to create an interface that will let me walk through a collection of objects, and access the name of the properties of the object.
A Report object will have ReportSections. A ReportSection will have an ICollection of items which will change depending on usage.
Here's how I'm trying to define it now.
public interface IReport
{
string ReportName { get; set; }
ICollection<IReportSection> ReportSections { get; }
}
public interface IReportSection
{
string ReportSectionName { get; set; }
ICollection ReportItems { get; }
}
public abstract class ReportBase : IReport
{
virtual public string ReportType { get; set; }
virtual public string ReportName { get; set; }
virtual public ICollection<IReportSection> ReportSections { get; set; }
}
public abstract class ReportSectionBase : IReportSection
{
public string ReportSectionName { get; set; }
public ICollection ReportItems { get; set; }
}
In my code, I would do this:
public class BookAffiliates : ReportSectionBase
{
public override string ReportSectionName { get { return "Book Affiliates"; } }
public override ICollection ReportItems { get; set; }
}
public class SomeClass
{
public ICollection<AuthorsViewModel> Authors { get; set; }
public ICollection<ProjectSubmissionViewModel> Submissions { get; set; }
public string ProcessAuthorsReport()
{
var report = new ContribAuthorsReport{ ReportType = "CSV" };
var authorAffil = new BookAffiliates {ReportItems = Authors };
report.ReportSections.Add(chapAffil);
var submissionAffil = new BookAffiliates {ReportItems = Submissions};
report.ReportSections.Add(submissionAffil );
return RenderReport(report)
}
}
In RenderReport I would like to walk through the collections and use the PropertyNames:
private string RenderReport(ReportBase currentReport)
{
var reportBody = new StringBuilder();
reportBody.Append(currentReport.ReportName + Environment.NewLine + Environment.NewLine);
foreach (var thisSection in currentReport.ReportSections)
{
reportBody.Append(thisSection.ReportSectionName + Environment.NewLine);
/// ---- Here! Here! I don't know what type, I want the
/// code to get the type based on ReportSectionBase<T>
var firstItem = thisSection.ReportItems.OfType<???Type???>().FirstOrDefault();
// I would actually like to go through each property of
// the ReportItem type and list it here.
foreach(var prop in firstItem.GetType().GetProperties())
{
reportBody.AppendLine(string.Format("{0}:{1}" prop.Name, prop.Value));
}
}
return reportBody.ToString();
}
I'm not sure how to best define this. I'm pretty sure I've done it before, but it's not coming to me.
You would use Reflection to do it.
foreach(var prop in thisItem.GetType().GetProperties())
{
reportBody.AppendLine(string.Format("{0}:{1}" prop.Name, prop.Value));
}
Took a while, a lot of questions, and figuring out what I really wanted to ask. I came up with this.
Here are my interfaces and base classes:
public class ReportBase
{
public ReportBase()
{
ReportSections = new List<IReportSection>();
}
public string ReportType { get; set; }
public string ReportName { get; set; }
public ICollection<IReportSection> ReportSections { get; set; }
}
public interface IReportSection
{
string ReportSectionName { get; }
ICollection ReportItems { get; set; }
}
public class ReportSection<T> : IReportSection
{
public string ReportSectionName { get; set; }
public ICollection<T> ReportItems { get; set; }
ICollection IReportSection.ReportItems
{
get { return ReportItems as ICollection; }
set { ReportItems = value as ICollection<T>; }
}
}
I create my objects like this:
public ReportBase GetContribAuthorsReport
(
ICollection<ProjectAffiliateViewModel> projectAffiliates,
ICollection<SubmissionAffiliateViewModel> submissionAffiliates
)
{
//var caReport = new ContributingAffiliates("CSV", projectAffiliates, submissionAffiliates);
var caReport = new ReportBase { ReportType = "CSV", ReportName = "Reviewers' Contact Information" };
caReport.ReportSections.Add(new ReportSection<ProjectAffiliateViewModel> { ReportItems = projectAffiliates });
caReport.ReportSections.Add(new ReportSection<SubmissionAffiliateViewModel> { ReportItems = submissionAffiliates });
return caReport;//.Report;
}
Then I iterate through the objects like this:
public class DownloadCsvActionResult : ActionResult
{
public ReportBase Report { get; set; }
public string fileName { get; set; }
private string ReportData { get; set; }
public DownloadCsvActionResult(ReportBase report, string pFileName)
{
Report = report;
fileName = pFileName;
ReportData = RenderReport();
}
private string RenderReport()
{
var reportBody = new StringBuilder();
reportBody.AppendLine(Report.ReportName);
reportBody.Append(Environment.NewLine + Environment.NewLine);
foreach (var thisSection in Report.ReportSections)
{
reportBody.Append(thisSection.ReportSectionName + Environment.NewLine);
if (thisSection.ReportItems != null)
{
var itemType = thisSection.ReportItems.GetType().GetGenericArguments().Single();
var first = true;
foreach (var prop in itemType.GetProperties())
{
if (!first) reportBody.Append(",");
DisplayAttribute attribute = prop.GetCustomAttributes(typeof(DisplayAttribute), false)
.Cast<DisplayAttribute>()
.SingleOrDefault();
string displayName = (attribute != null) ? attribute.Name : prop.Name;
reportBody.Append(displayName);
first = false;
}
reportBody.Append(Environment.NewLine);
foreach (var thisItem in thisSection.ReportItems)
{
var firstData = true;
foreach (var prop in itemType.GetProperties())
{
if (!firstData) reportBody.Append(",");
reportBody.Append(prop.GetValue(thisItem,null));
firstData = false;
}
reportBody.Append(Environment.NewLine);
}
}
reportBody.Append(Environment.NewLine);
}
return reportBody.ToString();
}
public override void ExecuteResult(ControllerContext context)
{
//Create a response stream to create and write the Excel file
HttpContext curContext = HttpContext.Current;
curContext.Response.Clear();
curContext.Response.AddHeader("content-disposition", "attachment;filename=" + fileName);
curContext.Response.Charset = "";
curContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
curContext.Response.ContentType = "application/vnd.ms-excel";
//Write the stream back to the response
curContext.Response.Write(ReportData);
curContext.Response.End();
}
}
This gives me what I need for now. Sorry I wasn't as clear in the first place, and thank you for all your help.
I have a model structure as illustrate below.
public class GuideLineSectionsViewModel
{
public GuideLineSectionsViewModel()
{
SectionsSet = new List<SectionViewModel>();
}
public string Title { get; set; }
public List<SectionViewModel> SectionsSet { get; set; }
}
public class SectionViewModel
{
public SectionViewModel()
{
SectionsSet = new List<SectionViewModel>();
QuestionsSet = new List<QuestionViewModel>();
ProblemsSet = new List<ProblemViewModel>();
GoalsSet = new List<GoalViewModel>();
BarriersSet = new List<BarriersViewModel>();
QuestionReferencesSet = new List<QuestionReferenceViewModel>();
}
public string Heading { get; set; }
public List<SectionViewModel> SectionsSet { get; set; }
public List<QuestionViewModel> QuestionsSet { get; set; }
public List<ProblemViewModel> ProblemsSet { get; set; }
public List<GoalViewModel> GoalsSet { get; set; }
public List<BarriersViewModel> BarriersSet { get; set; }
public List<QuestionReferenceViewModel> QuestionReferencesSet { get; set; }
}
public class ProblemViewModel
{
public string Text { get; set; }
public bool Identified { get; set; }
public List<GoalViewModel> GoalsSet { get; set; }
public List<QuestionReferenceViewModel> QuestionReferencesSet { get; set; }
}
Now Based on the condition I need to update the every list value of the ProblemViewModel using linq.Below is the condition
public GuideLineSectionsViewModel FindGuidelineType(GuideLineSectionsViewModel guidelineSectionModel)
{
//GuideLineSectionsViewModel result = new GuideLineSectionsViewModel();
string title = guidelineSectionModel.Title;
int count = Regex.Matches(title, "Low Intensity").Count;
if (count > 0)
{
}
return guidelineSectionModel;
}
The guidelineSectionModel.Title will contain the text as "some value : Low Intensity". So i used the regx to filter the text. Is there other way i can directly check the condition in linq. and update the model model.
I want to update list value of ProblemViewModelmodel property value public bool Identified to "true"
Currently it contain only False value.
Please can anyone help me to solve the issue.
Have a look at following method. I could not put LINQ but I think this answer can solve your purpose. Again Some classes structure are missing in your question so you may need to put that in following method.
GuideLineSectionsViewModel FindGuidelineType(GuideLineSectionsViewModel guidelineSectionModel)
{
//GuideLineSectionsViewModel result = new GuideLineSectionsViewModel();
string title = guidelineSectionModel.Title;
int count = Regex.Matches(title, "Low Intensity").Count;
if (count > 0)
{
foreach(SectionViewModel svm in guidelineSectionModel.SectionsSet)
{
foreach(ProblemViewModel pvm in svm.ProblemsSet)
{
pvm.Identified = true;
}
}
}
return guidelineSectionModel;
}
If you prefer LINQ:
if(guideLine.Title.Contains("Low Intensity"))
{
guideLine.SectionsSet.ForEach(s => s.ProblemsSet.ForEach(ps => ps.Identified = true));
}
Note: please read this answer https://stackoverflow.com/a/2962689/1525637 due to possible performance problems with the Regex.Matches, you should use String.Contains instead.
i am working on a small app that mange flights, i have a class that build a flight details and class that build the passenger, now, i want to load the passengers onto a flight, how should i do it? do i need to build a higer class that inherit from this two class and make a list of that type of class(i dont think that wise oop ).or should i add a ticket prop in the passenger class that have the flight number, here is my code.
public class Passenger
{
public Passenger(string name, int passportNumber)
{
this.PassengerName = name;
this.PassportNumber = passportNumber;
}
private string _passengerName;
public string PassengerName
{
get { return _passengerName; }
set { _passengerName = value; }
}
private int _passportNumber;
public int PassportNumber
{
get { return _passportNumber; }
set { _passportNumber = value; }
}
}
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
{
this.FlightNumber = flightNumber;
this.FlightDestination = flightDestination;
this.PlanModel = planmodel;
}
private int _flightNumber;
public int FlightNumber
{
get { return _flightNumber; }
set { _flightNumber = value; }
}
private string _flightDestination;
public string FlightDestination
{
get { return _flightDestination; }
set { _flightDestination = value; }
}
private string _planeModel;
public string PlanModel
{
get { return _planeModel; }
set { _planeModel = value; }
}
}
static void Main(string[] args)
{
List<FlightDetails> flightList = new List<FlightDetails>();
FlightDetails a = new FlightDetails(12,"france","jumbo");///create a flight
flightList.Add(a);/// load up the flight
}
First, you can't create a class that inherits from both other classes because multiply inheritance is not allowed in C#.
You can use aggregation, something like this:
public class FlightDetails
{
// ...
}
public class Passenger
{
// ...
}
public class Flight
{
public FlightDetails { get; private set; }
public List<Passenger> Passengers { get; private set; }
public Flight(FlightDetails details)
{
FlightDetails = details;
Passengers = new List<Passenger>();
}
public AddPassenger(Passenger p)
{
// check for ticket and so on..
Passengers.Add(p);
}
}
You can read more about aggregation here: http://en.wikipedia.org/wiki/Object_composition#Aggregation
Note that in this example for simplicity i used List but actually you need to limit access to this array (because otherwise i can do something like this: Flight.Passengers.Add(p) instead of Flight.AddPassenger(p)) so good idea will be use ReadOnlyCollection as public interface to this list.
Here's a sample code that might work. A flight has one or more passengers, thus has a List of type Passenger. In real-life, a passenger can book multiple flights. If you want the reality, you'll have to change your model but for this situation it'll work:
public class Passenger
{
public Passenger(string name, int passportNumber)
{
PassengerName = name;
PassportNumber = passportNumber
}
public string PassengerName { get; set; }
public int PassportNumber { get; set; }
}
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
{
FlightNumber = flightNumber;
FlightDestination = flightDestination;
PlanModel = planmodel;
Passengers = new List<Passengers>();
}
public int FlightNumber { get; set; }
public string FlightDestination { get; set; }
public string PlanModel { get; set; }
public List<Passenger> Passengers { get; private set; }
public void AddPassenger(string name, int number)
{
int max = 2;
int passengersNumber = Passengers.Count;
if (passengersNumber < max)
{
Passengers.Add(new Passenger(name, number);
}
}
public static void Main(string[] args)
{
var flightList = new List<FlightDetails>();
var passengersList = new List<Passenger>();
//Add passenger-objects to passengers-list
var flightOne = new FlightDetails(12, "France", "Jumbo");
flightOne.Passengers = passengersList;
flightList.Add(a);
}
Here's a better solution to limit the passengers:
public class FlightDetails
{
public FlightDetails(int flightNumber, string flightDestination, string planmodel)
: this(flightNumber, flightDestination, planmodel, new List<Passenger>())
{
}
public FlightDetails(int flightNumber, string flightDestination, string planmodel, List<Passenger> passengers)
{
FlightNumber = flightNumber;
FlightDestination = flightDestination;
PlanModel = planmodel;
if(passengers.Count > 2)
//throw exception or error
else
_passengers = passengers;
}
private List<Passenger> _passengers = new List<Passenger>();
public int FlightNumber { get; set; }
public string FlightDestination { get; set; }
public string PlanModel { get; set; }
public IEnumerable<Passenger> Passengers { get { return _passengers; } }
public void AddPassenger(string name, int number)
{
int max = 2;
int passengersNumber = _passengers.Count;
if (passengersNumber < max)
{
_passengers.Add(new Passenger(name, number);
}
}
}
Note: this code is written without compiling. But the idea is correct normally. :)
In logical way, relation between FlightDetail to Passenger is OneToMany. One FlightDetail can have multiple Passenger which is can be written as below. FlightDetail and Passenger should be have any common inheritance hierarchy because they are don't have any common attribute or behaviour.
public class FlightDetails
{
private List<Passenger> passengerList;
public void addPassenger(Passenger p){
if(passengerList == null){
passengerList = new ArrayList<Passenger>();
}
passengerList.add(p);
}
public List<Passenger> getPassengerList(){
return passengerList;
}
//... your other detail
}
You should add a FlightDetails property to your Passenger class. That's easier than making a List with PassportNumber as index. But, it's easier to iterate FlightDetails using List, than accessing it through Passenger.
It actually depends on how you want to access and store the relations.
It might be a good idea to read about the composite pattern which actually has a nice solution for travelling between parent-child relations, even though the pattern has another purpose.
if i compiled below codes error return foreach loop how can i solve it?
Error:Error 1 foreach statement cannot operate on variables of type 'Sortlist.MyCalısan' because 'Sortlist.MyCalısan' does not contain a public definition for 'GetEnumerator' C:\Users\yusuf.karatoprak\Desktop\ExcelToSql\TestExceltoSql\Sortlist\Program.cs 46 13 Sortlist
static void EskiMetodlaListele()
{
MyCalısan myCalısan = new MyCalısan();
Calısan calisan = new Calısan();
calisan.Ad = "ali";
calisan.SoyAd = "abdullah";
calisan.ID = 1;
myCalısan.list.Add(calisan);
foreach (Calısan item in myCalısan)
{
Console.WriteLine(item.Ad.ToString());
}
}
}
public class Calısan
{
public int ID { get; set; }
public string Ad { get; set; }
public string SoyAd { get; set; }
}
public class MyCalısan
{
public List<Calısan> list { get; set; }
public MyCalısan()
{
list = new List();
}
}
Only write foreach (Calısan item in myCalısan.list).
I recommend MyCalısan to define as Collection.
public class MyCalısan : Collection<Calısan>
{
}
You should loop on MyCalisan.list; MyCalisan is just your class, and is not enumerable itself.
a few issues need to be fixed before it will compile:
public class MyCalısan{
public List<Calısan> list { get; set; }
public MyCalısan()
{
list = new List<Calısan>();
}}
foreach (Calısan item in myCalısan.list)
{
Console.WriteLine(item.Ad.ToString());
}
You need to iterate over the collection you had defined - the list property:
myCalısan.list.Add(calısan);
foreach (Calısan item in myCalısan.list)
{
Console.WriteLine(item.Ad.ToString());
}
However, if you want to iterate over myCalısan directly, make the MyCalısan class implement IEnumerable<Calısan>.