replacing variable in elements of a List - c#

A more simple example might be:
List <myElement> Elements;
Elements.Add(my1);
Elements.Add(my2);
my1 and my2 eache have a variable of type string named myString
Now I want to change the value of my1.myString. But if I change it the value my2.myString gets changed aswell.
Hopefully it's a bit clearer now
I'm using a List with several Elements within it in C#. The List has as type a self-defined class with several variables in it.
Now I want to change in one list-element the value of a variable. But unfortunately the value gets replaced not only on this but in all elements of this list.
Any advice on how to fix this?
MyProjectElement File1 = this.Project.Elements[0];
MyProjectElement File2 = this.Project.Elements[1];
MyProject my1 = (MyProject)File1;
MyProject my2 = (MyProject)File2;
PageCount_F1 = my1.PageCount;
PageCount_F2 = my2.PageCount;
if (PageCount_F1 != PageCount_F2)
MessageBox.Show("The 2 files need to have the same file length", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
else
{
my1.IncludeAllPages = false;
my2.IncludeAllPages = false;
for(int i=1; i <= PageCount_F1; i++)
{
StringBuilder value1 = new StringBuilder();
StringBuilder value2 = new StringBuilder();
value1.Append("" + i);
value2.Append("" + (PageCount_F2-i+1));
MyProject my1new = new MyProject();
MyProject my2new = new MyProject();
my1new.Pages = value1.ToString();
my2new.Pages = value2.ToString();
my1.Pages = my1new.Pages;
my2.Pages = my2new.Pages;
this.Project.Elements.Add((myProjectElement)my1);
this.Project.Elements.Add((myProjectElement)my2);
((MyProject)this.Project.Elements[1]).Pages.Remove(0);
((MyProject)this.Project.Elements[i]).Pages.Remove(0);
((MyProject)this.Project.Elements[1]).Pages = "" + 1;
((MyProject)this.Project.Elements[PageCount_F2 - i + 1]).Pages = "" + (PageCount_F2 - i + 1);
((MyProject)this.Project.Elements[i-1]).Pages.Remove(0);
((MyProject)this.Project.Elements[i]).Pages.Remove(0);
((MyProject)this.Project.Elements[i - 1]).Pages = "" + i;
((MyProject)this.Project.Elements[i]).Pages = "" + (PageCount_F2 - i + 1);
}

You need to specify what the condition is to make a change. For example:
myList.ForEach(x => if(whateverCondition) x.myString = "blah" );
But you really need to ascertain what that condition is.

The problem is that in the code that you've put up you're changing your values in a loop that steps through every element and the loop starts indexing the List with index 1, whereas the first element in index 0.
If you're only after changing one element then select that element. Moo-Juice has posted a good suggestion (+1 btw).
p.s. don't post links to external stores with your code, many users that sit behind corporate firewalls can't access them.

Related

C# - Editing Listbox Items

I'm making an app in Windows Forms that simulates a Point of Sales. I'm creating now the part where the user clicks on a product button and it adds to a listbox an item like this: "'Quantity' - 'Name of the product' - 'cost'".
When the button is clicked again is supposed to edit the item like this: "'Quantity+1' - 'Name of the product' - 'cost*2'".
However it just add another item with that information.
So far, my code is the following:
private void bprod1_Click(object sender, EventArgs e)
{
MySqlCommand cmdp1 = new MySqlCommand("SELECT preco_unitario FROM produtos where designacao='" + bprod1.Text + "';", mConn);
mConn.Open();
MySqlDataReader drp1 = cmdp1.ExecuteReader();
drp1.Read();
string getpreco1 = drp1["preco_unitario"].ToString();
mConn.Close();
quant1 = quant1 + 1;
var preco1tot = quant1 * Convert.ToDecimal(getpreco1);
var text1 = quant1.ToString() + " - " + bprod1.Text + " - " + preco1tot.ToString();
listvenda.Items.Add(text1);
}
bprod1 is my button. quant1 starts with value 0. getpreco1 is the value I get from the database (product's cost).
My objective is, when clicked the second time and so on, increase the quantity and add the cost without creating a new item.
I could just delete the item and add another one with the new info, but I want the item to be in the same place as the other, and not on the end of the list.
I appreciate any suggestions and help.
Hope you guys understand what I intend to do.
This line:
listvenda.Items.Add(text1);
is why you're seeing a new item every single time. A mature application would be more likely to use either private class or Model approaches.
Create a new class file within the same namespace and call it something. See below:
public class myProduct
{
public int Quantity {get; set;}
public int Name {get; set;}
public double Price {get; set;}
public myProduct(string name)
{
this.Quantity = 1; this.Name = name; this.Price = 0;
}
public override string ToString()
{
return this.Quantity.ToString() + "-" + this.Name + "-" +
(this.Price * this.Quantity).ToString(c,
CultureInfo.CurrentCulture);
}
}
Now, where you were just adding values, you can check to see if the line exists, and if it does, operate on it. Otherwise, add a new line. Don't bother with ToString() methods and such, as you can actually populate your listbox with a list of the new class! It will call the ToString() method when displaying values.
List<myProduct> listvendaBind = new List<myProduct>();
///insert code here to build your list from the database if you havent already. Otherwise, skip this step so you dont overwrite your list
//now the code for modification
var x = listvendaBind.Where(t => t.Name == newProduct.Name).FirstOrDefault();
if(x.Count() > 0 && (x != null)
listvendaBind[listvendaBind.IndexOf(x[0])].Quantity++;
else
listvendaBind.Add(newProduct);
listvenda.DataSource = listvendaBind;
This is untested, as I'm working on another project at the moment, but should serve as proof of concept.
This is only for learning and I do not recommended using it outside testing environment but you can do something like this:
insetad of
listvenda.Items.Add(text1);
do this:
bool notFound = true;
for(int i=0; i<listvenda.Items.Count; i++)
{
if(((string)listvenda.Items[i]).Contains(" - " + bprod1.Text + " - "))
{
listvenda.Items[i] = text1;
notFound = false;
break;
}
}
if(notFound)
listvenda.Items.Add(text1);
but as I said it should only be temporary solution. Instead of this use CDove solution

C# - Fetching a JSON nested Array value

Im trying to find an answer for this but i must be searching for the wrong terms.
Im working on a Windows phone app and am getting data from an API with a nested array value "user.username"
void data_arrived(object sender, DownloadCompleteData e)
{
String data = e.data;
JArray obj = JArray.Parse(data);
for (int i = 0; i < obj.Count; i++)
{
JObject row = JObject.Parse(obj[i].ToString());
var item = new DataList();
item.country = row["title"].ToString() + " (€" + row["price"].ToString() + ") ";
item.code = row["price"].ToString();
item.imageURL = row["urlimage"].ToString();
item.votes = row["votes"].ToString();
item.category = row["category"].ToString();
item.username = row["user.username"].ToString();
list.Items.Add(item);
}
}
Everything else works fine except user.username
How do i use this properly?
Thanks
You can deserialize a valid JSON string to a dynamic object. This will allow you access to underlying object using dot notation. e.g.
dynamic row = JsonConvert.DeserializeObject (obj[i].ToString());
Your final code block inside loop will look like
dynamic row = JsonConvert.DeserializeObject(obj[i].ToString());
Console.WriteLine(row.title.ToString() + " (€" + row.price.ToString() + ") ");
Console.WriteLine(row.price.ToString());
Console.WriteLine(row.urlimage.ToString());
Console.WriteLine(row.votes.ToString());
Console.WriteLine(row.category.ToString());
Console.WriteLine(row.user.username.ToString());
Console.WriteLine();
Console.WriteLine("-----------------------------\n");
There is no "easy" way to achieve this because the . in C# is reserved.
However, you could achieve something pretty close by using a dictionary and collection initializer. It's still somewhat isolated, and doesn't require you to create a custom class.
var obj = new Dictionary<string, object>
{
{ "user.username", "myvalue" }
};
var json = JsonConvert.SerializeObject(obj);
//{"user.username":"myvalue"}

Parsing an UN XML file in C#

I'm trying to parse an XML file from UN website (http://www.un.org/sc/committees/1267/AQList.xml) using c#.
There is one problem I'm constantly having with this file, and that's the number of child tags varies from one <.INDIVIDUAL.> tag to another. One example is <.FORTH_NAME.> child tag.
I've tried a number of different approaches, but somehow I always seem to be stuck with the same problem, and that's different number of child tags inside <.INDIVIDUAL.> tag.
What I'm trying to achieve is to collect all the tags and their values under one <.INDIVIDUAL.> tag, and then insert only those I want into my database. If a tag is missing, for example <.FOURTH_NAME.>, than I need to insert only first three names into the database, and skip the fourth.
I've tried using Linq to XML, and here are some examples:
XDocument xdoc = XDocument.Load(path);
var tags = (from t in xdoc.Descendants("INDIVIDUALS")
from a in t.Elements("INDIVIDUAL")
select new
{
Tag = a.Name,
val = a.Value
});
foreach (var obj in tags)
{
Console.WriteLine(obj.Tag + " - " + obj.val + "\t");
//insert SQL goes here
}
or:
but this one only collects non empty FOURTH_NAME tags...
var q = (from c in xdoc.Descendants("INDIVIDUAL")
from _1 in c.Elements("FIRST_NAME")
from _2 in c.Elements("SECOND_NAME")
from _3 in c.Elements("THIRD_NAME")
from _4 in c.Elements("FOURTH_NAME")
where _1 != null && _2 != null && _3 != null && _4 != null
select new
{
_1 = c.Element("FIRST_NAME").Value,
_2 = c.Element("SECOND_NAME").Value,
_3 = c.Element("THIRD_NAME").Value,
_4 = c.Element("FOURTH_NAME").Value
});
foreach (var obj in q)
{
Console.WriteLine("Person: " + obj._1 + " - " + obj._2 + " - " + obj._3 + " - " + obj._4);
//insert SQL goes here
}
Any ideas??
Instead of calling Value on the element, consider using a string cast. LINQ to XML safely returns null if the element doesn't exist. Try the following:
var data = XElement.Load(#"http://www.un.org/sc/committees/1267/AQList.xml");
var individuals = data.Descendants("INDIVIDUAL")
.Select(i => new {
First = (string)i.Element("FIRST_NAME"),
Middle = (string)i.Element("SECOND_NAME"),
Last = (string)i.Element("THIRD_NAME")
});
If you want to be more flexible and get all of the name fields, you can do something like the following. (I'll leave the process of grouping individuals as an additional homework assignment ;-)
data.Descendants("INDIVIDUAL").Elements()
.Where (i =>i.Name.LocalName.EndsWith("_NAME" ))
.Select(i => new { FieldName= i.Name.LocalName, Value=i.Value});
Why don't you use XmlSerializer and LINQ instead ?
As explained in this answer, generate your classes by pasting in a new CS file :
menu EDIT > Paste Special > Paste XML As Classes.
Then grab your data as easily as follows :
var serializer = new XmlSerializer(typeof (CONSOLIDATED_LIST));
using (FileStream fileStream = File.OpenRead(#"..\..\aqlist.xml"))
{
var list = serializer.Deserialize(fileStream) as CONSOLIDATED_LIST;
if (list != null)
{
var enumerable = list.INDIVIDUALS.Select(s => new
{
FirstName = s.FIRST_NAME,
SecondName = s.SECOND_NAME,
ThirdName = s.THIRD_NAME,
FourthName = s.FOURTH_NAME
});
}
}
You can then specify any predicate that better suits your needs.
Going this path will be a huge time-saver and less error-prone, no need to use strings to access fields, strong typing etc ...

quick and simple way to sort this data taken from a tsv and make it distinct as per one of the fields that it contains

I want to know the quickest and simplest way to sort the code shown below. Sorting from newRecord.AppCode would not be suitable as it will change the meaning of the output. So I need to sort every line from string outp. What would be the best way? Also I would like to make every row distinct. I beleive using LINQ would be very quick but I am not that great at it. Help appreciated. So close to getting it done! Note: Data is being pulled from a tsv. Using .net 3.5, visual studio 2008) Will mark answer as soon as I get progress. :)
while ((line = sr.ReadLine()) != null)
{
String[] splitted = line.Split('\t');
appcodes.Add(line);
Records newRecord = new Records();
newRecord.Server = splitted[0];
newRecord.Instance = splitted[1];
newRecord.AppCode = splitted[2];
newRecord.Database = splitted[3];
listrecords.Add(newRecord);
for (int i = 0; i < appcodes.Count(); i++)
{
if (newRecord.AppCode==appcodes[i].ToUpper())
{
String outp = newRecord.AppCode + " " + newRecord.Server + " " + newRecord.Instance + " " + newRecord.Database;
Console.WriteLine(outp);
}
}
}
have lists named Keepers and newkeepers. Was trying to do something like outp.sort() and outp.sort() but it doesnt work in strings. This is how I solved the problem.
Keepers.Add(outp);
Keepers.Sort();
newKeepers = Keepers.Distinct().ToList();
foreach (object o in newKeepers)
{
Console.WriteLine(o);
}
Console.ReadLine();
As you can see, newrecords contain different fields so I wrote a LINQ statement to solve the problem.
var sorted_list = (from r in newrecords
orderby r.AppCode, r.Server, r.Instance, r.Database
select r).Distinct().ToList();
var distinctSortedList = sorted_list.Distinct().ToList();

Add string to array only if data is available

I have some code that builds a string array using data from a form:
string[] var4 = new string[] {
"Issue=" + DropDownListIssue.SelectedItem.ToString(),
"SubIssue=" + DropDownListSubIssue.SelectedItem.ToString(),
"Layout=" + DropDownListLayout.SelectedItem.ToString()
};
This code adds all the elements to the array even if there is no data. For example, say the value of Issue is "Apple," but the other two dropdownlists are left blank. The resulting var4 would be this:
"Issue=Apple"
"SubIssue="
"Layout="
In this case, I would like var4 to be:
"Issue=Apple"
SubIssue and Layout are not added to the array as they are left blank. If they are filled in, however, then they should be added to the array. Example:
"Issue=Apple"
"SubIssue=Dog"
"Layout=Square"
How can I write this to only add the string when it has a value?
You can do the following:
string[] possibleNulllVar4 = new string[] {
string.IsNullOrEmpty(DropDownListIssue.SelectedItem.ToString()) ? "Issue=" + DropDownListIssue.SelectedItem.ToString() : null,
string.IsNullOrEmpty(DropDownListSubIssue.SelectedItem.ToString()) ? "SubIssue=" + DropDownListSubIssue.SelectedItem.ToString() : null,
string.IsNullOrEmpty(DropDownListLayout.SelectedItem.ToString()) ? "Layout=" + DropDownListLayout.SelectedItem.ToString() : null
};
Edit: Ah, if you don't want any empty nodes, do the following afterward:
var var4 = possibleNulllVar4.Where(x => null != x).ToArray();
Easy!
List<string> list = new List<string>();
var str = DropDownListIssue.SelectedItem.ToString();
if (!string.IsNullOrEmpty(str))
list.Add("Issue=" + str);
str = DropDownListSubIssue.SelectedItem.ToString();
if (!string.IsNullOrEmpty(str))
list.Add("SubIssue=" + str);
str = DropDownListLayout.SelectedItem.ToString();
if (!string.IsNullOrEmpty(str))
list.Add("Layout=" + str);
string[] var4 = list.ToArray();
I'm on a phone so please forgive some of the grammar / spelling / code sample if it doesn't work as is...
But the generic idea is this:
Why not loop through a collection of those DropDown lists, if one has a selected value, add the value to the passed in array (or use an Arraylist.ToArray() or List.ToArray()) so yo udon't need to redim it. Each dropdown can have a argument/command on it, so you'd know which one you're dealing with:
Similar to (PSEUDO)
List<DropDowns> dropDowns = ...//Get your dropdowns into the list
foreach(dd in dropDowns)
{
if(dd.SelectedItem != null && d.SelectedIndex != -1 )
YourStringArray.Add(dd.CommandArgument + "=" + dd.SelectedValue);
}
Sorry - on phone so it might not "compile" but that's why I marked id pseduo. Doing a List<> and a Foreach isn't the most efficient, but it gets away from ugly massive if statements.

Categories

Resources