WPF C#. put observablecollection into List<string> - c#

I have observablecollection which i fill with textboxes on button click event. In my Project is one class where i have list >> public List _RoomNumber = new List(); i want to just send observablecollection value into _RoomNumber list. For example if observablecollection cotains this 4 values : 15, 20, 2323, 3232 i want _RoomNumber context be same so this : 15, 20, 2323, 3232
I hope my question is clear.
This my observablecollection :
ObservableCollection<CheckInData> _CheckInCollection = new ObservableCollection<CheckInData>();
public ObservableCollection<CheckInData> CheckInCollection
{
get { return _CheckInCollection; }
}
public class CheckInData
{
public string RoomNumber { get; set; }
public decimal Price { get; set; }
public string Currecny { get; set; }
public decimal Discount { get; set; }
public string CheckOut { get; set; }
public int TotalDay { get; set; }
public decimal TotalPrice { get; set; }
public int CheckOutYear { get; set; }
public int CheckOutMonth { get; set; }
public int CheckOutDay { get; set; }
public Boolean IncToday { get; set; }
}
this is how im trying to put in list. Problem is that observablecollection contains 102 and 305. _RoomNumber only gets value '1'. please help
private void btnPrintInvoice_Click(object sender, RoutedEventArgs e)
{
//This is Class where my List _RoomNumber is
DataToExcel.Invoice inv = new DataToExcel.Invoice();
foreach (CheckInData coll in CheckInCollection)
{
for (int i = 0; i < _CheckInCollection.Count; i++)
{
inv._RoomNumber.Add(coll.RoomNumber[i].ToString());
}
}
}

You need to make small modification. Try this:
private void btnPrintInvoice_Click(object sender, RoutedEventArgs e)
{
//This is Class where my List _RoomNumber is
DataToExcel.Invoice inv = new DataToExcel.Invoice();
foreach (CheckInData coll in CheckInCollection)
{
inv._RoomNumber.Add(coll.RoomNumber.ToString());
}
}
You don't need to access RoomNumber with index. It is not a collection.

You can use
var roomnumbers = CheckInCollection.Select(x => x.RoomNumber);
inv._RoomNumber = new List(roomnumbers);
Or if you want to reuse the existing List instance,
inv._RoomNumber.Clear();
inv._RoomNumber.AddRange(roomnumbers);
but this seems to be not your case.
Note that in your code, your both inner and outer loops iterate over the same collection :-)

using System.Linq;
...
ObservableCollection<string> ListA = new ObservableCollection<string>();
List<string> ListB = ListA.ToList<string>();

Related

How to share a list of objects without giving ability to modify their state?

Let's say I have a class StockMarket which has a list of Companies.
class StockMarket : IStock
{
private static List<IObserverPush> observersPush;
private static List<IObserverPull> observersPull;
public static List<Company> Companies { get; private set; }
public StockMarket()
{
observersPush = new List<IObserverPush>();
observersPull = new List<IObserverPull>();
Companies = new List<Company>() { new Company("Unilever", "UNA", 47.72, 0.77, 1.63, -3.45, "135B"),
new Company("ING Groep", "INGA", 13.40, -0.07, -0.50, -12.38, "60.4B"),
new Company("ArcelorMittal", "MT", 29.50, 0.14, 0.48, 36.05, "54.6B"),
new Company("ASML Holding", "ASML", 167.40, 2.00, 1.21, 36.49, "53.3B"),
new Company("Heineken", "HEIA", 87.66, -0.02, -0.02, 2.80, "49B"),
new Company("RELX", "REN", 18.15, 0.17, 0.95, -0.22, "38.9B"),
new Company("Philips", "PHIA", 35.49, 0.17, 0.47, 7.61, "33.3B"),
new Company("Unibail Rodamco", "UL", 196.40, -0.15, -0.08, -16.78, "20.3B"),
new Company("Akzo Nobel", "AKZA", 75.68, -0.16, -0.21, 0.33, "19.4B"),
new Company("Altice", "ATC", 7.58, 0.16, 2.16, -66.30, "17.6B")};
Thread thread = new Thread(SimulateMarket);
thread.Start();
}
public void Subscribe(IObserverPull o)
{
observersPull.Add(o);
o.UpdateMarket();
}
public void Unsubscribe(IObserverPull o)
{
observersPull.Remove(o);
}
public void Subscribe(IObserverPush o)
{
observersPush.Add(o);
o.UpdateMarket(Companies);
}
public void Unsubscribe(IObserverPush o)
{
observersPush.Remove(o);
}
public void NotifyObservers()
{
foreach(IObserverPush o in observersPush)
{
o.UpdateMarket(Companies);
}
foreach(IObserverPull o in observersPull)
{
o.UpdateMarket();
}
}
public void SimulateMarket()
{
while(observersPush.Count + observersPull.Count > 0)
{
//randomly change property values of companies
//and notify the observers about the changes
}
}
}
Company class has some properties.
public class Company
{
public string Name { get; private set; }
public string Symbol { get; private set; }
public double Price { get; set; }
public double Change { get; set; }
public double ChangePercentageDay { get; set; }
public double ChangePercentageYear { get; set; }
public string Capital { get; private set; }
public Company(string name, string symbol, double price, double change, double changePercentageDay,
double changePercentageYear, string capital)
{
Name = name;
Symbol = symbol;
Price = price;
Change = change;
ChangePercentageDay = changePercentageDay;
ChangePercentageYear = changePercentageYear;
Capital = capital;
}
}
The Forms have references to the StockMarket and they use it to retrieve data about the companies and to display it.
Form 1
public partial class ConcreteObserverPush : Form, IObserverPush
{
private StockMarket stockMarket;
public ConcreteObserverPush()
{
InitializeComponent();
stockMarket = new StockMarket();
stockMarket.Subscribe(this);
}
public void UpdateMarket(List<Company> companies)
{
stockMarketListView.Items.Clear();
foreach(Company c in companies)
{
ListViewItem item = new ListViewItem(c.Symbol);
item.SubItems.Add(c.Price.ToString());
item.SubItems.Add(c.Change.ToString());
item.SubItems.Add(c.ChangePercentageDay.ToString() + "%");
stockMarketListView.Items.Add(item);
}
}
private void ConcreteObserverPush_FormClosing(object sender, FormClosingEventArgs e)
{
stockMarket.Unsubscribe(this);
}
}
Form 2
public partial class ConcreteObserverPull : Form, IObserverPull
{
private StockMarket stockMarket;
public ConcreteObserverPull()
{
InitializeComponent();
stockMarket = new StockMarket();
stockMarket.Subscribe(this);
}
public void UpdateMarket()
{
stockMarketListView.Items.Clear();
foreach (Company c in StockMarket.Companies)
{
ListViewItem item = new ListViewItem(c.Symbol);
item.SubItems.Add(c.Name);
item.SubItems.Add(c.Price.ToString());
item.SubItems.Add(c.Change.ToString());
item.SubItems.Add(c.ChangePercentageDay.ToString() + "%");
item.SubItems.Add(c.ChangePercentageYear.ToString() + "%");
item.SubItems.Add(c.Capital);
stockMarketListView.Items.Add(item);
}
}
private void ConcreteObserverPull_FormClosing(object sender, FormClosingEventArgs e)
{
stockMarket.Unsubscribe(this);
}
}
The problem is that if the Form gets the list of companies through the property on StockMarket it can change their state. However, I want only StockMarket to have the ability to change the state of the company.
So what would be the best way to share Company state with Form when requested and preventing the Form from modifying it.
I know that a possible solution would be to return clones of Company objects, but I believe there should be a better solution.
Any help is appreciated!
The general gist of this would be to make your Company object immutable. Then you would add methods to the StockMarket object to manipulate the Company list and replace entries with new ones when you want to change a value.
Here's a quick example put together in LINQPad of making the Company class immutable and adding an UpdatePrice method to the StockMarket class.
Whether you want to be able to manipulate the Companies property from outside the StockMarket can be handled by returning the list as ReadOnlyCollection so that it's size can't be manipulated by a consumer.
void Main()
{
var sm = new StockMarket();
sm.Companies.Add(new Company("Test", "TST", 50, 0));
sm.UpdatePrice("Test", 45);
var testCompany = sm.Companies.First(x => x.Name == "Test");
Console.WriteLine($"{testCompany.Name},{testCompany.Symbol},{testCompany.Price},{testCompany.Change}");
//Output: Test,TST,45,-5
}
class StockMarket
{
public List<Company> Companies { get; private set; } = new List<Company>();
public void UpdatePrice(string name, double price) {
var index = Companies.FindIndex(x => x.Name == name);
if(index >= 0)
{
var previous = Companies[index];
Companies[index] = new Company(previous.Name, previous.Symbol, price, price - previous.Price);
}
}
}
class Company
{
public Company(string name, string symbol, double price, double change) {
Name = name;
Symbol = symbol;
Price = price;
Change = change;
}
public string Name { get; }
public string Symbol { get; }
public double Price { get; }
public double Change { get; }
///...
}
This would be a solution:
Create the Company class as a Private Inner Class inside of the StockMarket class, that way it'd only be accessible inside of it, and then provide an interface that only includes the get of all the properties and make Company implement it. You would have to make StockMarket's Company list to be the Interface's type.
Any modification you'd have to do you'd do it by casting the interface's List objects into the original class type.
Example:
class Program
{
public static StockMarket stockMarket = new StockMarket();
static void Main(string[] args)
{
}
}
public interface ICompany
{
string Name { get; }
}
public class StockMarket
{
public StockMarket()
{
Companies = SomeWildFunctionThatRetrievesAllCompanies();
}
public void OneWildFunctionThatModifiesACompany()
{
Company dunno = (Company)Companies[0];
dunno.Name = "Modification Made Possible";
}
private List<ICompany> SomeWildFunctionThatRetrievesAllCompanies()
{
return new List<ICompany>(new List<Company>());
}
public List<ICompany> Companies { get; private set; }
private class Company : ICompany
{
public string Name { get; set; }
}
}
Try this:
class Company
{
public Company(Type type,string name,string symbol,double price, double change)
{
if (type.Name == "StockMarket")
{
Name = name;
Symbol = symbol;
Price = price;
Change = change;
}
}
private string Name { get; set; }
private string Symbol { get; set; }
private double Price { get; set; }
private double Change { get; set; }
///...
}
This will allow you to change the state only if the type is StockMarket
like:
class StockMarket
{
public List<Company> Companies { get; set; }
public StockMarket()
{
Companies = new List<Company>();
}
public StockMarket someMethod()
{
//You can change the state here
StockMarket s = new StockMarket();
s.Companies.Add(new Company(this.GetType(), "aa", "_", 123, 1234));
return s;
}
//...
}
Now you cannot change the state here:
public partial class Observer: Form
{
private StockMarket stockMarket;
public ConcreteObserverPull()
{
InitializeComponent();
stockMarket = new StockMarket();
//Here you cannot change the state
stockMarket.Companies.Add(new Company(this.GetType(), "aa", "_", 123,12));
}
//...
}
Sorry, I don't know C#, but as an idea, you can wrap returned entities with decorator or proxy, which will throw an exception in case of trying to modify state of a company.
Returning clones with fields set as readonly is the safest way to go.

How to add to List Generic on each button clicks

I have a button that gets items from controls and add to a list.
As shown
This is my ojects thats holds the values.
public class SelectedPurchaseItems
{
public int ItemId { get; set; }
public string ItemName { get; set; }
public double PurchasePrice { get; set; }
public int Quantity { get; set; }
public string UnitOfMeasure { get; set; }
public double Total { get; set; }
}
This is my mainwindow class that does the adding to the list
public partial class MainWindow : Window
{
public List<SelectedPurchaseItems> SelectedList;
private void btnSaveModalSelectItem_Click(object sender, RoutedEventArgs e)
{
SelectedList = new List<SelectedPurchaseItems>();
SelectedPurchaseItems _value = new SelectedPurchaseItems()
{
ItemId = Convert.ToInt32(comboboxSelectItemItem.SelectedValue),
ItemName = comboboxSelectItemItem.Text,
PurchasePrice = _purchasePrice,
Quantity = _quantity,
UnitOfMeasure = comboboxSelectItemUnitofMeasure.Text,
Total = _total
};
SelectedList.Add(_value);
DataGridSelectedPurchaseItems.ItemsSource = SelectedList;
}
}
My challenge now is, any time it adds an item to the List, it always reinitialize the list, which makes the previous item added to clear off.
But my aim is for the List to hold each item that has been added to it, and i don't know how to go about that.
I'm also Binding the list to a WPF datagrid. So after showing the first added item, it won't display any further added item.
SelectedList = new List<SelectedPurchaseItems>();
is the line that reinitializes your list. You should just delete it, and move initial list initialization to a constructor or somwhere else
Dont re-instantiate it in the button click. Simply initialise it once as shown:
public partial class MainWindow : Window
{
public List<SelectedPurchaseItems> SelectedList = new List<SelectedPurchaseItems>();
public MainWindow()
{
DataGridSelectedPurchaseItems.ItemsSource = SelectedList;
}
private void btnSaveModalSelectItem_Click(object sender, RoutedEventArgs e)
{
SelectedPurchaseItems _value = new SelectedPurchaseItems()
{
ItemId = Convert.ToInt32(comboboxSelectItemItem.SelectedValue),
ItemName = comboboxSelectItemItem.Text,
PurchasePrice = _purchasePrice,
Quantity = _quantity,
UnitOfMeasure = comboboxSelectItemUnitofMeasure.Text,
Total = _total
};
SelectedList.Add(_value);
}
}

Using one list across many functions

I have a class of houses (the channel enum is not displayed here)
The class has objects referenced and two constructors, and then inside the class there is a List called 'inventory' and two or more functions that try to access the list, What I'd like to do is use this same list across all of the separate functions inside of 'class houses'
but I am getting a 'does not exist in current context' error, Which makes me think this is a problem of scope.
But all the methods are in the same 'class houses' ... Aren't they of the same scope?
Obviously not following the right path, How should I look at this?
class property
{
public string AddressNumber { get; set; }
public string AddressStreet { get; set; }
public double ListingPrice { get; set; }
public double MonthlyRent { get; set; }
public double Taxes { get; set; }
public Channel Channel { get; set; }
public property(string addnum, string addstreet, double lp, double mr, double taxes, Channel rorm)
{
AddressNumber = addnum;
AddressStreet = addstreet;
ListingPrice = lp;
MonthlyRent = mr;
Taxes = taxes;
Channel = rorm;
}
public property()
{
AddressNumber = "4319";
AddressStreet = "Forestview";
ListingPrice = 600000;
MonthlyRent = 0;
Taxes = 2000;
Channel = Channel.Rosa;
}
static List<property> inventory = new List<property>
{
new property("19263","Collingham",24000,700,1744, Channel.Rosa),
new property("16003","Collingham",24000,700,1672, Channel.Rosa),
new property("13051","Bringard",24000,700,1305, Channel.Rosa),
new property("10409","Bringard",24000,650,1591, Channel.Rosa),
new property("10086","Marne",24000,650,1176, Channel.Rosa),
new property("10042","Peerless",24000,650,1313, Channel.Rosa),
new property("10736","Steel",30000,1000,1587, Channel.Mike),
new property("2010","Glendale",30000,1000,1587, Channel.Mike),
new property("2260","Blain",30000,1000,1587, Channel.Mike),
new property("3000","Fullerton",30000,1000,1587, Channel.Mike),
};
property addtolist= new property("864", "Alter", 30000, 650, 1600, Channel.Rosa);
inventory.Add(addtolist);
public static void userAddItem()
{
//I want to use the list here
}
public static void allItemsToFile()
{
//and here
}
} //end of house class bracket
You should think of your classes as objects. So your house class can just be a object that defines a house.
public class houses
{
public string AddressNumber { get; set; }
public string AddressStreet { get; set; }
public double ListingPrice { get; set; }
public double MonthlyRent { get; set; }
public double Taxes { get; set; }
public Channel Channel { get; set; }
}
Now, you want to make a list of properties. In your main class, you can do something like this;
private List<houses> properties = new List<houses>();
houses house1 = new houses();
house1.AddressNumber = "19263";
house1.AddressStreet = "Collingham";
house1.ListingPrice = 24000.0;
hosue1.MonthlyRent = 700.0;
house1.Taxes = 1744.0;
house1.Channel = Channel.Rosa;
properties.Add(house1);
Now you have a list of properties and you can access them as you need.
Foreach(houses h in properties)
{
Console.WriteLine("{0},{1},{2},{3},{4},{5}", h.AddressNumber, h.AddressStreet, h.ListingPrice, h.MonthlyRent, h.Taxes, h.Channel.toString());
}

Subset List of parent List not binding to Listbox in Winforms

I am trying to bind a List of a custom class to a Listbox and cannot get anything to display. The List is a subset of another List. I can bind the parent List and see the items, but not the child List. How can I get the subset List to bind to the Listbox? I have tried changing the order of the ListBox's DisplayMember, ValueMember, and DataSource properties. In debugging I can see that the DataSource has the correct values, but I can't get them to display. Relevant code below:
public class DimZone
{
public int Zone_Key { get; set; }
public int Zone_ID { get; set; }
public int Facility_Key { get; set; }
public string Zone_Name { get; set; }
public string Zone_Type { get; set; }
}
GlobalVariables Class containing global List collection:
public static List<DimZone>[] zoneCollection = new List<DimZone>[maxServerCount];
Form using global List collection and subset List:
List<DimZone> zoneCollectionAppended = new List<DimZone>();
private void StaffStatusReportForm_Load(object sender, EventArgs e)
{
facilityComboBox.DataSource = GlobalVariables.facilityCollection;
GetFacilityIndex();
CreateZoneAppendedList();
PopulateUI();
}
private void CreateZoneAppendedList()
{
foreach (var zone in GlobalVariables.zoneCollection[currentFacilityIndex])
{
if (zone.Zone_Name != "All")
{
zoneCollectionAppended.Add(zone);
}
}
}
private void PopulateUI()
{
if (zoneCollectionAppended != null)
{
zoneListBox.DisplayMember = "Zone_Name";
zoneListBox.ValueMember = "Zone_ID";
zoneListBox.DataSource = zoneCollectionAppended;
}
}
Your code contains various unclear parts. In any case, the best proceeding in these situations is setting up a properly-working simpler code and modifying it until reaching the stage you want. I can provide this properly-working first step. Sample code:
private void Form1_Load(object sender, EventArgs e)
{
List<DimZone> source = new List<DimZone>();
DimZone curZone = new DimZone() { Zone_Key = 1, Zone_ID = 11, Facility_Key = 111, Zone_Name = "1111", Zone_Type = "11111" };
source.Add(curZone);
curZone = new DimZone() { Zone_Key = 2, Zone_ID = 22, Facility_Key = 222, Zone_Name = "2222", Zone_Type = "22222" };
source.Add(curZone);
zoneListBox.DisplayMember = "Facility_Key";
zoneListBox.DataSource = source;
}
public class DimZone
{
public int Zone_Key { get; set; }
public int Zone_ID { get; set; }
public int Facility_Key { get; set; }
public string Zone_Name { get; set; }
public string Zone_Type { get; set; }
}
Try this code and confirm that the changes in zoneListBox.DisplayMember (e.g., "Zone_Key", "Zone_ID", etc.) are immediately reflected in the values being displayed by zoneListBox.
The problem was I was changing zoneListBox.DataSource from one source to another on load, which caused the error. In order for the DataSource to update properly, I had to set zoneListBox.DataSource = null before updating to a new DataSource. I don't know why I have to set it to null first, but it solved my problem. So my updated code is as follows:
private void PopulateUI()
{
if (zoneCollectionAppended != null)
{
zoneListBox.DisplayMember = "Zone_Name";
zoneListBox.ValueMember = "Zone_ID";
//DataSource had to be reset to null before updating to new DataSource
zoneListBox.DataSource = null;
zoneListBox.DataSource = zoneCollectionAppended;
}
}

C# accessing IEnumerable collections

I am fairly new to working with collections so please bear with me my jargon might not even be accurate.
I have PetaPoco returning query results as an IEnumerable, one collection for each result. I want to evaluate the collections to get a specific string from a specific field in each collection. So far I am able to iterate the Enumerable and seeming able to get access an object as per my snippet below but when i view c.Language in debug, it is only the first character of the string (eg where c.Language should equal "JPY" it equals only "J")
am I doing this completely wrong? Thanks for the advice
public void AddContactOrder(object sender, EventArgs e)
{
IEnumerable OrderFact = new OrdersFactsController().getOrderFacts(base.ModuleId);
IEnumerator enumerator = OrderFact.GetEnumerator();
var test = "";
List<string> lang = new List<string>();
while (enumerator.MoveNext())
{
OrderFact c = (OrderFact)enumerator.Current;
if (c.Language == "JPY")
{
test = "okay";
}
}
}
getorderFacts() returns an IEnumerable where T is OrderFact
public class OrderFact
{
public int ID { get; set; }
public int ModuleId { get; set; }
public string ProdCode { get; set; }
public string Language { get; set; }
public string Currency { get; set; }
public string KeyCodes { get; set; }
public string OrderSourceCode { get; set; }
public string OfferingCode { get; set; }
public string JobNumber { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime ModifiedDate { get; set; }
}
You're better off just using a foreach loop:
foreach (var c in new OrdersFactsController().getOrderFacts(base.ModuleID))
{
if (c.Language == "JPY")
test = "okay";
}
You could use System.Linq's Any extension method:
public void AddContactOrder(object sender, EventArgs e)
{
var orderFacts = new OrdersFactsController().getOrderFacts(base.ModuleId);
var test = orderFacts.Any(x => x.Language == "JPY") ? "okay" : "";
}
public void AddContactOrder(object sender, EventArgs e)
{
IEnumerable<OrderFact> orderFacts = new OrdersFactsController().getOrderFacts(base.ModuleId);
var test = "";
if(orderFacts.Any(x => x.Language == "JPY")) test="okay";
}
LINQ!

Categories

Resources