display list items into data grid view c# - c#

I have a super-class (abstract) and then 2 inherited classes.
SuperClass: Sessions
Class 1: Cycling
Class 2: Running
I also have a list that will hold all of my objects private List<Session> allSessions = new List<Session>();
I also have declared some arrays that hold hard-coded data to populate my objects.
Also, Running and Cycling has an overridden ToString() method that displays different data depending on the class.
public override string ToString() => $"Cycle Average RPM is {AverageRpm} and Average Resistance is {AverageResistance}";
I am using a for loop to create and add new objects into my list like this
for (int i = 0; i < id.Length; i++)
{
Cycling Cycle = new Cycling(id[i], titles[i], date[i], duration[i], difficulty[i], instructor[i],
description[i], averageRpm[i], averageResistance[i]);
// Add new objects to list
allSessions.Add(Cycle);
}
I have a dataGridView that is getting everything from my list and displays it like this:
My problem now is, that I want to display only specific data depending on what you choose in the ComboBox, but something is not working,
The overridden ToString() is not added to the list for some reason and whenever I choose a different option from the ComboBox, nothing is being displayed.
EDIT 1:
// Filter Sessions by type using Linq
var sessions = new List<Session>();
var cyclingSessions = sessions.OfType<Cycling>();
var runningSessions = sessions.OfType<Running>();
listBox1.DataSource = null;
listBox1.Items.Clear();
if (cboMenu.SelectedIndex == 0)
{
// Populate GridView with data
dataDisplay.DataSource = allSessions;
}
else if (cboMenu.SelectedIndex == 1)
{
// Populate GridView with data
dataDisplay.DataSource = cyclingSessions;
}
else
{
// Populate GridView with data
dataDisplay.DataSource = runningSessions;
}
}

You need to filter your sessions list and set that as your data source you can easily filter the list using OfType from System.Linq It would look something like this:
var sessions = new List<Sessions>();
var cyclingSessions = sessions.OfType<Cycling>();
var runningSessions = sessions.OfType<Running>();
dataDisplay.DataSource = cyclingSessions;

Related

How do I store the initial state of a list of objects so that I can compare them to an updated list?

I have a list that is constantly being updated throughout my program. I would like to be able to compare the initial count and final count of my list after every update. The following is just a sample code (the original code is too lengthy) but it sufficiently captures the problem.
class Bot
{
public int ID { get; set; }
}
public class Program
{
public void Main()
{
List<Bot> InitialList = new List<Bot>();
List<Bot> FinalList = new List<Bot>();
for (int i = 0; i < 12345; i++)
{
Bot b = new Bot() {ID = i};
InitialList.Add(b);
}
FinalList = InitialList;
for (int i = 0; i < 12345; i++)
{
Bot b = new Bot() {ID = i};
FinalList.Add(b);
}
Console.Write($"Initial list has {InitialList.Count} bots");
Console.Write($"Final list has {FinalList.Count} bots");
}
}
Output:
Initial list has 24690 bots
Final list has 24690 bots
Expected for both lists to have 12345 bots.
What is correct way to copy the initial list so new set is not simply added to original?
To do what you seem to want to do, you want to copy the list rather than assign a new reference to the same list. So instead of
FinalList = InitialList;
Use
FinalList.AddRange(InitialList);
Basically what you had was two variables both referring to the same list. This way you have two different lists, one with the initial values and one with new values.
That said, you could also just store the count if that's all you want to do.
int initialCount = InitialList.Count;
FinalList = InitialList;
Although there's now no longer a reason to copy from one to the other if you already have the data you need.
I get the feeling you actually want to do more than what's stated in the question though, so the correct approach may change depending on what you actually want to do.

Sorting List Array based on an index of array

I want to sort a List Array on the basis of an array item.
I have a List Array of Strings as below:
List<String>[] MyProjects = new List<String>[20];
Through a loop, I have added five strings
(Id, Name, StartDate, EndDate, Status)
to each of the 20 projects from another detailed List source.
for(int i = 0; i<20; i++){
MyProjects[i].Add(DetailedProjectList.Id.ToString());
MyProjects[i].Add(DetailedProjectList.Name);
MyProjects[i].Add(DetailedProjectList.StartDate);
MyProjects[i].Add(DetailedProjectList.EndDate);
MyProjects[i].Add(DetailedProjectList.Status)}
The Status values are
"Slow", "Normal", "Fast", "Suspended" and "" for unknown status.
Based on Status, I want to sort MyProject List Array.
What I have done is that I have created another List as below
List<string> sortProjectsBy = new List<string>(){"Slow", "Normal", "Fast", "", "Suspended"};
I tried as below to sort, however unsuccessful.
MyProjects = MyProjects.OrderBy(x => sortProjectsBy.IndexOf(4));
Can anyone hint in the right direction. Thanks.
I suggest you to create class Project and then add all the fields inside it you need. It's much nicer and scalable in the future. Then create a List or an Array of projects and use the OrderBy() function to sort based on the field you want.
List<Project> projects = new List<>();
// Fill the list...
projects.OrderBy(project => project.Status);
The field Status has to be a primitive type or needs to implement the interface IComparable in order for the sorting to work. I suggest you add an enum for Status with int values.
First consider maybe to use Enum for status and put it in a different file lite (utils or something) - better to work like that.
enum Status {"Slow"=1, "Normal", "Fast", "", "Suspend"}
Now about the filtering you want to achieve do it like this (you need to tell which attribute of x you are referring to. In this case is status)
MyProjects = MyProjects.OrderBy(x => x.status == enum.Suspend);
Read about enums :
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum
Read about lambda expressions :
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
First of all, storing project details as List is not adivisable. You need to create a Custom Class to represent them.
For example,
public class DetailedProjectList
{
public string Name {get;set;}
public eStatus Status {get;set;}
// rest of properties
}
Then You can use
var result = MyProjects.OrderBy(x=> sortProjectsBy.IndexOf(x.Status));
For example
List<string> sortProjectsBy = new List<string>(){"Slow", "Normal", "Fast", "", "Suspended"};
var MyProjects= new List<DetailedProjectList>{
new DetailedProjectList{Name="abc1", Status="Fast"},
new DetailedProjectList{Name="abc2", Status="Normal"},
new DetailedProjectList{Name="abc3", Status="Slow"},
};
var result = MyProjects.OrderBy(x=> sortProjectsBy.IndexOf(x.Status));
Output
abc3 Slow
abc2 Normal
abc1 Fast
A better approach thought would be to use Enum to represent Status.
public enum eStatus
{
Slow,
Normal,
Fast,
Unknown,
Suspended
}
Then your code can be simplified as
var MyProjects= new List<DetailedProjectList>{
new DetailedProjectList{Name="abc1", Status=eStatus.Fast},
new DetailedProjectList{Name="abc2", Status=eStatus.Normal},
new DetailedProjectList{Name="abc3", Status=eStatus.Slow},
};
var result = MyProjects.OrderBy(x=> x.Status);
Ok so you have a collection of 20 items. Based on them you need to create a list of strings(20 DetailedProjectList items).
What you can do to solve your problem is to SORT YOUR COLLECTION before you create your list of strings. In this way your list of strings will be sorted.
But your code is not optimal at all. So you should concider optimization on many levels.
Lets say you have ProjectDetail class as follow:
private class ProjectDetail
{
public int Id {get;set;}
public string Name {get;set;}
DateTime StartDate {get;set;} = DateTime.Now;
DateTime EndDate {get;set;} = DateTime.Now;
public string Status {get;set;}
public string toString => $"{Id} - {Name} - {StartDate} - {EndDate} - {Status}";
}
Notice that I have added a toString attribute to make things easier, and I also have added default values.
Then your program could be like:
static void Main(string[] args)
{
var projectDetails = MockProjectItems();
Console.WriteLine("Before sortig:");
foreach (var item in projectDetails)
{
Console.WriteLine(item.toString);
}
var myProjects = projectDetails.OrderBy(p => p.Status).Select(p => p.toString);
Console.WriteLine("\n\nAfter sorting:");
foreach (var item in myProjects)
{
Console.WriteLine(item);
}
}
where the helper method is
private static List<ProjectDetail> MockProjectItems()
{
var items = new List<ProjectDetail>(20);
for(int i = 0; i < 20 ; i += 4){
items.Add(new ProjectDetail{Id = i, Name = "RandomName "+i, Status = "Slow"});
items.Add(new ProjectDetail{Id = i+1, Name = "RandomName "+(i+1), Status = "Normal"});
items.Add(new ProjectDetail{Id = i+2, Name = "RandomName "+(i+2), Status = "Fast"});
items.Add(new ProjectDetail{Id = i+3, Name = "RandomName "+(i+3), Status = "Suspended"});
}
return items;
}
Then your program should print the following:

MVC List Error List<Model>

I'm using foreach to transfer data from list to another but when adding value updated automatically to last value added. For example:
list1 = [1,2,3]
list2 = new List<Model>()
foreach(var item in list1) {
list2.Add(item)
}
the result in list2 is [ 3, 3, 3]
Actually example is below :
var _sizes = new List<ProductsSize>();
var _size = new ProductsSize();
if (model.Dynamic_ProductsSize.Count > 0)
{
foreach (var item in model.Dynamic_ProductsSize)
{
_size.SizeId = item;
_sizes.Add(_size);
}
}
model.ProductsSize = _sizes.ToList();
I need to know why it only takes the last item and what is the solution for this case
You only have one ProductsSize object:
var _size = new ProductsSize();
And you keep modifying that same object. All references to that object, including any list elements it's been added to, get updated when you modify that one object.
Instead, create your new object in the loop:
foreach (var item in model.Dynamic_ProductsSize)
{
var _size = new ProductsSize();
_size.SizeId = item;
_sizes.Add(_size);
}
That way each element in the list is a new object instead of the same object added multiple times.
Side note, you have a few things in the code which aren't necessary. Checking the length before the loop, for example, as well as converting a list to a list at the end.
In fact, I imagine all of the code shown can be shortened to simply this:
model.ProductsSize = model.Dynamic_ProductsSize.Select(p => new ProductsSize { SizeId = p }).ToList();
In which case you're also just converting one model property to another model property. Why not put this logic in the model itself and skip the whole thing?
public IEnumerable<ProductsSize> ProductsSize
{
get { return this.Dynamic_ProductsSize.Select(p => new ProductsSize { SizeId = p });
}
Unless there's a particular reason you want the same data twice in two different properties that isn't clear from this code, having one set of data and just different views/calculations/etc. of that data is often preferred.
Create a new object before adding it to the list. You can use the object initializer syntax to keep it concise:
if (model.Dynamic_ProductsSize.Count > 0)
{
foreach (var item in model.Dynamic_ProductsSize)
{
_sizes.Add(new ProductsSize(){SizeId = item});
}
}

WCF - list in ComboBox

I'd like to get country's names form one field of list and put them to the comboBox:
public TravelAgencyResponse GetInformation(TravelAgencyRequest request)
{
TravelAgencyResponse response = new TravelAgencyResponse();
// response.Offers = new OfferDto();
response.Offers = new List<DataTransferObjects.OfferDto>();
response.Offers.Add(new DataTransferObjects.OfferDto()
{
IdOffer = 0,
KindOfAccommodation = "Hotel",
Country = "Spain",
});
response.Offers.Add(new DataTransferObjects.OfferDto()
{
IdOffer = 1,
KindOfAccommodation = "Hotel",
Country = "Italy",
});
response.ThisOffer = (from offer in response.Offers
where offer.Country == request.Country
select offer).FirstOrDefault();
return response;
}
I thought that I can use LINQ without FirstOrDefault() but I can't do that in this situation.
private void button1_Click(object sender, EventArgs e)
{
Uri baseAddr = new Uri("http://localhost:1232/TravelAgencyService/SimpleTravelAgencyService/");
ChannelFactory<ITravelAgencyService> factory = new ChannelFactory<ITravelAgencyService>(new WSHttpBinding(),
new EndpointAddress(baseAddr));
ITravelAgencyService proxy = factory.CreateChannel();
var response = proxy.GetInformation(
new TravelAgencyService.Messages.TravelAgencyRequest()
{
Country = textBox1.Text
});
comboBox1.Items.Add(response.ThisOffer.Country);
listBox1.Items.Add(response.ThisOffer.Country);
}
I tried put these information in ComboBox like that:
comboBox1.Items.Add(response.ThisOffer.Country);
and I give only the first country or like that:
comboBox1.Items.Add(response);
and I don't get anything.
my first steps with WCF! Be understanding, please!
So if I understand your question correctly, you want to fill a ComboBox with all the countries that are contained in any response.Offers's Country property, correct?
Since you mentioned you are new to WPF, I'll skip the part about MVVM and DataBinding and show you a way it can be done with what you have now.
First you need to "extract" all the countries from the Offers, preferably only once and sorted alphabetically.
List<string> countries = response.Offers
.Select(o => o.Country) // We only need the "Country" of the offer
.Distinct() // Every country only once
.OrderBy(c => c) // Sort by name
.ToList(); // make a List<string> out of it
Instead of adding items manually, I'd recommend assigning all of them at once, by setting the DataSource property.
comboBox1.DataSource= countries;
You need to make sure however that Items is empty, manually added items and DataSource do not work well together.
If you want to pre-select a certain country (e.g. the one from ThisOffer) you can set the SelectedItem property of the ComboBox:
comboBox1.SelectedItem = response.ThisOffer.Country;

Show results based on two items from array or more

I've been struggling for hours now trying to figure out, how to display data based on array items using linq c#.
In short i am displaying data based on results from a querystring that passes into an array.
this works great with one array item.
but if i navigate to another page that has two or more array items, i want to be able to say only show me results that contains x,y,z. Code below:
public static List<business.Resource> getResourcesFromTags(string[] tags)
{
var db = new Entities();
List<business.Resource> resources = (
from rt in db.tbl_ResourceTag
where tags.Any(t =>t.Equals(rt.tbl_Tag.Name))
select new Resource {
bookmark = rt.tbl_Resource.Bookmark,
dateAdded = rt.tbl_Resource.dateAdded,
text = rt.tbl_Resource.text,
uploadedFile = rt.tbl_Resource.uploadedFile,
uploadedImage = rt.tbl_Resource.uploadedImage,
resourceID = rt.tbl_Resource.ResourceID,
filePath = rt.tbl_Resource.filePath,
imagePath = rt.tbl_Resource.imagePath,
downloadCount = rt.tbl_Resource.downloads
}).Distinct().ToList();
return resources;
}
So to re-cap if there is more than one array item, i want to be able to show data contains just those items. very difficult to explain.

Categories

Resources