I'm taking XML, filtering and putting it into a combobox, and my issue is taking the selected combobox entry, and saving each individual piece. Here is some sample XML im using.
<SolutionString>
<Solutions>
<Solution>
<ID>1</ID>
<Property>
<Name>DriverSheave</Name>
<Value>1VP34</Value>
</Property>
<Property>
<Name>DriverBushing</Name>
<Value>
</Value>
</Property>
<Property>
<Name>DrivenSheave</Name>
<Value>AK49</Value>
</Property>
<Property>
<Name>DrivenBushing</Name>
<Value>
</Value>
</Property>
</Solution>
<Solution>
<ID>2</ID>
...ect(ID 2, ID 3 and so on). After this im sticking these XML results into my combobox like this.
XmlDocument doc1 = new XmlDocument();
doc1.LoadXml(XmlString.ToString());
PTS.Library.VbeltDriveLibrary.Configurator Configurator = new PTS.Library.VbeltDriveLibrary.Configurator(doc1);
if (Configurator.SolveAndValidate())
{
var solutions = Configurator.Results.ToXDocument();
int i = 0;
var indexesToChoose = new List<int> { 9, 8, 4, 5, 0, 2, 7, 6 };
var cat = solutions
.Descendants("Solution")
.Select(x => new
{
ID = (string)x.Element("ID"),
Properties = x.Elements("Property").Select(p => new
{
Name = (string) p.Element("Name"),
Value = (string) p.Element("Value"),
idx = (i < 11 ? i++ : i = 0)
})
.Where(y => indexesToChoose.Contains(y.idx))
.OrderBy(z => indexesToChoose.FindIndex(p => p == z.idx))
.ToList()
});
var items = cat
.Select(s => new
{
ID = s.ID,
Text = string.Format("{0}. {1}", s.ID,
string.Join(", ", s.Properties
.Select(p => string.Format("{0} = {1}",
p.Name,
p.Value ?? "(null)"))))
}).ToArray();
comboBox1.DisplayMember = "Text";
comboBox1.ValueMember = "ID";
comboBox1.Items.AddRange(items);
Finally, i want to be able to take this selection,(this is the selected items in the combobox)
Cost = 1072.93, ActualDrivenShaftSpeed = 900/1073, Belt = B84, BeltQty = 5, DriverSheave = 5MVP70B84P, Comment2 = Correct tension for this drive (1.31 lb. should deflect belt 0.48 in.) will have 30 lb. 'running' Hub Load, DrivenSheave = 5MVB70R, ActualServiceFactor = 40.63, ActualCenterDistance = 30.8
and filter each piece out into a variable, for example,
string ActualCenterDistance = 30.8
Obviously i can put the whole selection into a string easily with a simple combobox.selectedText, however putting each piece into individual strings (or any other var) is my issue.
It looks like a bad design for me.
Consider instead of using anonymous type here:
.Select(x => new
{
ID = (string)x.Element("ID"),
Properties = x.Elements("Property").Select(p => new
just create instance of your own class which could be like:
public class MyItem
{
public string ID;
public List<Tuple<string, string>> Properties;
public string GetProperty(string name)
{
if (Properties == null)
return null;
var item = Properties.FirstOrDefault(x => x.Item1 == name);
return item == null ? null : item.Item2;
}
public override string ToString()
{
return string.Join(", ", Properties
.Select(p => string.Format("{0} = {1}",
p.Item1,
p.Item2 ?? "(null)")));
}
}
in this case (since I've transferred logic of concatenation Name/Value of properties to ToString method override of MyItem class) - you can fill combobox with items having type of MyItem, and you will be able to access all your data easily like:
var item = comboBox1.SelectedItem as MyItem;
string x = item.GetProperty("DriverSheave");
Changes to be made with the code:
var items = solutions.Descendants("Solution")
.Select(x => new MyItem
{
ID = (string)x.Element("ID"),
Properties = x.Elements("Property").Select(p => new
{
Name = (string)p.Element("Name"),
Value = (string)p.Element("Value"),
idx = (i < 11 ? i++ : i = 0)
})
.Where(y => indexesToChoose.Contains(y.idx))
.OrderBy(z => indexesToChoose.FindIndex(p => p == z.idx))
.Select(z => new Tuple<string, string>(z.Name, z.Value))
.ToList()
}).ToArray();
comboBox1.DisplayMember = "Text";
comboBox1.ValueMember = "ID";
comboBox1.Items.AddRange(items);
Note: this is essentially important to have some custom class as Item for combobox, because in the case of anonymous type being used you will not be able to access its fields when taking object from combobox.SelectedItem.
Related
I have a dictionary which has more than 2000+ elements. I am trying to update an element in the value based on a condition. How do I do that in a simple statement instead of looping through?
Dictionary<int, MyObj> testDictionary = new Dictionary<int, MyObj>();
testDictionary.Add(1,new MyObj() {Name = "John",Code = "JN",Id = null});
testDictionary.Add(2,new MyObj() {Name = "John",Code = "JN",Id = null});
testDictionary.Add(3,new MyObj() {Name = "Champ",Code = "CP",Id = null});
testDictionary.Add(4,new MyObj() {Name = "SMITH",Code = "SH",Id = null});
testDictionary.Add(5,new MyObj() {Name = "SMITH",Code = "SH",Id = null});
Dictionary<int, MyObj>
public class MyObj
{
public string Name { get; set; }
public string Code { get; set; }
public int? Id { get; set; }
}
How do I update all of Dictionary values (MyObj)
where Code = JN and Name = John with 100
where Code = SH and Name = SMITH with 989
I can get matched list using below statement but do I ressign to dictionary?
var enList = testDictionary.Values.Where(d => d.Name == "John" && d.Code == "JN");
Try the code bellow, this change the value of name to test attribute in any item where the value of Name is "SMITH".
testDictionary.Where(y => y.Value.Name == "SMITH")
.Select(r => r.Value)
.ToList<MyObj>()
.ForEach(k => k.Name = "test");
This line does not return result, the value is changed directly in the textDictionary instance.
Look at the example - you don't need to reassign values in the Dictionary, they are stored as references.
var enList = testDictionary.Values.Where(d => d.Name == "John" && d.Code == "JN").ToList();
foreach (var item in enList)
{
item.Name = "Updated Name";
}
Console.WriteLine(testDictionary[1].Name);
Basically, if the user selected no option from the dropdown combo, I want it to be left out from my Linq query that looks something like this:
// this is how I manage the form post data, please
// propose a better way if you know one
Dictionary<string, string> formdata = new Dictionary<string, string>();
foreach(string key in Request.Form.AllKeys)
{
formdata.Add(key, Request.Form[key]);
}
// getting the title
string title = "";
formdata.TryGetValue("postedTitle", out title);
// getting the level
string levelString = "";
formdata.TryGetValue("postedLevel", out levelString );
int level = -1;
if(levelString != "")
{
Int32.TryParse(levelString , out level);
}
var model = new FooIndexVM
{
Foos = _ctx.SomeDbSet.Where(w => w.Title.Contains(title) && w.Level == (Level?)level.Value).Select(x => new FooBarRow
{
FooBarId = x.Id,
....
Since I'm getting either 0 or -1 for the level -- I need a way to gracefully leave the Enum part from the query completely. I will also later add some additional fields similar to this one (may be unselected) so the solution will also work for those, I guess.
You can chain Where commands so this line:
Foos = _ctx.SomeDbSet.Where(w => w.Title.Contains(title) && w.Level == (Level?)level.Value).Select(x => new FooBarRow
{
FooBarId = x.Id,
....
Could be rewritten to be this without changing its behaviour (multiple Wheres effectively become combined with &&s):
Foos = _ctx.SomeDbSet.Where(w => w.Title.Contains(title)).Where(w => w.Level == (Level?)level.Value).Select(x => new FooBarRow
{
FooBarId = x.Id,
....
This then means that you can add some logic around whether to apply the second Where or not like this, for example:
var query = _ctx.SomeDbSet.Where(w => w.Title.Contains(title));
if (level != -1)
{
query = query.Where(w => w.Level == (Level?)level.Value)
}
Foos = query.Select(x => new FooBarRow
{
FooBarId = x.Id,
I want from json action result to return Id and Name property from certain object, so I decided to use KeyValuePair data type.
My question is how to inject data into KeyValuePair varaible from linq projection, for example
int id = 100;
string name = "john";
var data = repository.FindById(id);
var result = new KeyValuePair<int, string>();
result = data.Where(c=>c.Name == name)
.Select(x=>.x.Id)
.Select(a=>a.Name).FirstOrDefault();
You need to Select the KeyValuePair in your query.
int id = 100;
string name = "john";
var data = repository.FindById(id);
var result = data.Where(c=>c.Name == name)
.Select(x => new KeyValuePair<int,string>(x.Id, x.Name))
.FirstOrDefault();
Explicit way - maybe better readable - would be
var kv = new KeyValuePair<int, string>
{
Key = data.Where(c => c.Name == name).Select(x =>.x.Id).FirstOrDefault(),
Value = data.Where(c => c.Name == name).Select(a => a.Name).FirstOrDefault()
};
I am trying get data from the xml. Below is the code which
gets data from the XDocument and return list<t>.
However, p.Element("Sponsor") can sometimes be null. How can I check for the null values
var atClauseList = doc.Descendants(CLAUSE_GROUP_TAG).Descendants(AT_CLAUSE_TAG).Select(p => new AtClause()
{
ClauseNumber = (string)p.Element("Number"),
Sponsors = p.Element("Sponsor").Elements(SPONSOR_TAG).Select(y => y.Value)
.ToList(),
Page = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Page").ElementValueNull(),
Line = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Line").ElementValueNull(),
LineText = p.Element("Sponsor").Element("aItem").Element("AmendText").Nodes().OfType<XText>().FirstOrDefault().XTextValueNull(),
ItalicText = p.Element("Sponsor").Element("aItem").Element("AmendText").Element("Italic").ElementValueNull(),
ParaList = p.Element("Sponsor").Element("aItem").Element("AmendText").Elements("Para").Select(L => new Para
{
ParaText = (string)L,
Number = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Number"),
Quote = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Quote"),
}
).ToList()
}).ToList();
move your code out of an object initializer, and add some logic to it:
var atClauseList = new List<AtClause>();
foreach(var item in doc.Descendants(CLAUSE_GROUP_TAG).Descendants(AT_CLAUSE_TAG))
{
var atClause = new AtClause();
atClause.ClauseNumber = (string)item.Element("Number");
var sponsor = item.Element("Sponsor");
if (sponsor != null)
{
atClause.Sponsors = sponsor.Elements(SPONSOR_TAG).Select(y => y.Value).ToList();
atClause.Page = sponsor.Element("aItem").Element("AmendText").Element("Page").ElementValueNull();
atClause.Line = sponsor.Element("aItem").Element("AmendText").Element("Line").ElementValueNull();
atClause.LineText = sponsor.Element("aItem").Element("AmendText").Nodes().OfType<XText>().FirstOrDefault().XTextValueNull();
atClause.ItalicText = sponsor.Element("aItem").Element("AmendText").Element("Italic").ElementValueNull();
atClause.ParaList = sponsor.Element("aItem").Element("AmendText").Elements("Para").Select(L => new Para
{
ParaText = (string)L,
Number = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Number"),
Quote = ((System.Xml.Linq.XElement)(L)).AttributeValueNull("Quote"),
}).ToList();
atClauseList.Add(atClause);
}
You can use sequences rather than leaving the IEnumerable immediately:
var value = (string)p.Elements("Sponsor")
.Elements("aItem")
.Elements("AmendText")
.Elements("Page")
.SingleOrDefault()
I have some inbound XML that I am trying to read with LINQ to generate a list of objects:
<SCResponse>
<link href="http://192.168.6.126:8001/affiliate/account/81/notifications?startRow=2&limit=20" rel="next_page" title="Next"/>
<link href="http://192.168.6.126:8001/affiliate/account/81/notifications?startRow=1&limit=20" rel="previous_page" title="Previous"/>
<RecordLimit>20</RecordLimit>
<Notifications>
<Notification href="http://192.168.6.126:8001/affiliate/account/81/notifications/24">
<NotificationDate>2013-03-15T16:41:37-05:00</NotificationDate>
<NotificationDetails>Notification details 1</NotificationDetails>
<Status>New</Status>
<NotificationTitle>Test notification 1</NotificationTitle>
</Notification>
</Notifications>
<RecordsReturned>1</RecordsReturned>
<StartingRecord>1</StartingRecord>
<TotalRecords>1</TotalRecords>
And I've created a simple POCO object to represent a 'Notification':
public class Notification
{
public System.DateTime notificationDate;
public string notificationDetails;
public string status;
public string notificationTitle;
public string href;
}
and I'd like to read the incoming XML and create a list of objects.
List<Notification> notificationList;
XElement x = XElement.Load(new StringReader(result));
if (x != null && x.Element("Notifications") != null)
{
notificationList = x.Element("Notifications")
.Elements("Notification")
.Select(e => new Notification()
.ToList();
}
I'm really unclear about the 'e' part and how to initialize a new Notification object. Can ya help?
e is just a parameter name your passing to the lambda expression, new Notification(). You can use it like this:
notificationList = x.Element("Notifications")
.Elements("Notification")
.Select(e => new Notification()
{
href = (string)e.Attribute("href")
notificationDetails = (DateTime)e.Element("NotificationDate")
notificationDate = (string)e.Element("NotificationDetails")
status = (string)e.Element("Status")
notificationTitle = (string)e.Element("NotificationTitle")
}
.ToList();
Or if you prefer query syntax
notificationList =
(from e in x.Element("Notifications").Elements("Notification")
select new Notification()
{
href = (string)e.Attribute("href")
notificationDetails = (DateTime)e.Element("NotificationDate")
notificationDate = (string)e.Element("NotificationDetails")
status = (string)e.Element("Status")
notificationTitle = (string)e.Element("NotificationTitle")
})
.ToList();
Use object initialization syntax:
notificationList = x.Element("Notifications")
.Elements("Notification")
.Select(e => new Notification()
{
href = (string)e.Attribute("href"),
notificationDate = (DateTime)e.Element("NotificationDate"),
notificationDetails = (string)e.Element("NotificationDetails"),
status = (string)e.Element("Status"),
notificationTitle = (string)e.Element("NotificationTitle")
})
.ToList();
Remember, that you can easily cast objects like XElement and XAttribute into string, int, double, DateTime and more. Complete list can be found here: XElement Type Conversions
notificationList = x.Element("Notifications")
.Elements("Notification")
.Select(e => new Notification()
{
notificationDate = DateTime.Parse(e.Element("NotificationDate").Value),
notificationDetails = e.Element("NotificationDetails").Value,
status = e.Element("Status").Value,
notificationTitle = e.Element("NotificationTitle").Value,
href = e.Attribute("href").Value
}
.ToList();