I have a for each loop as follows:
foreach (PCparts parts in items)
{
MessageBox.Show(parts.PartName);
}
The loop returns 4 values in the following order: MOBO, GFX, CPU, and RAM
Now my question is, is there a way to store just one particular value into a variable or even just display it somewhere else like in a label or whatever? For example, store GFX into a variable that can be used later.
If you haven't noticed yet, I classify myself as a newbie so please don't be too harsh. I am trying to learn.
Since you have items defined as List<PCParts>, you can access the objects in the list anytime you want, so long as items is in scope.
So, for example, if you had a label (call it lblName for sake of the example), then you could do this:
lblName.Text = items[1].PartName;
Where items[1] is the second PCParts in the list (GFX).
Essentially, sine you have the list, you already have the data stored and can retrieve it. You will need to know which item your looking for, if you're looking for a specific one. For example, to build on your for each loop:
for each (PCpart part in items)
{
if (part.PartName == "GFX")
{
lblName.Text = part.PartName;
}
}
You could also use similar logic to store a selected value in a variable for further use:
string selectedPartName = items[1].PartName;
Without knowing more about what you are trying to do, it's hard to give a more definitive answer.
In the interest of giving a different, yet equally useful answer to Tim, PCParts would be more amenable to this kind of operation if it were a Dictionary rather than a List. You'd be able to access the value corresponding to the "GFX" key with an expression like items["GFX"].
Related
NOTE: at this time I am stuck on 2sxc v9.43.2 on this project.
After selecting a set of records from my Content Type, I need to be able to duplicate them changing 1 of the fields along the way. Here is my almost-working idea so far. The use case is simple, they have Programs that people can register for. They change each Season, but only a little (prices, dates/times, etc). And they need the Current Season live and unchanged while they edit the Next Season. So we are still in the fall season (EntityId 1732) with 97 active programs. We want to click a button and clone all 97 programs as is, but IN TO the new Next Season (1735 below).
Two questions:
if this way works, what syntax would work on ent/Attributes to delivery the "object" as needed in the fields.Add() line
is there another 2sxc way to do this? Some other variant of the App.Data.Create() method or some other method in the API? I just need to duplicate the record with 1 field (Season) changed?
is there a better way to do this in the latest versions of 2sxc, v11.7+ ?
// we are going to duplicate the current Season's programs in to the new season
// cheating for now, pre-made new 1735 in Seasons, current is 1732
var programs = AsDynamic(App.Data["Programs"])
.Where(p => ((List<DynamicEntity>)p.Season).First().EntityId == selectedSeason.EntityId);
// #programs.Count() // 97
foreach(var copy in programs)
{
var fields = new Dictionary<string, object>();
var ent = AsEntity(copy);
foreach(var attr in ent.Attributes)
{
if(attr.Key == "Season")
{
fields.Add(attr.Key, new List<int> { 1735 });
}
else
{
fields.Add(attr.Key, ent.GetBestValue(attr.Key)); // object??
}
}
App.Data.Create("Programs", fields);
}
There are at least 3 ways to clone
Simple way using edit-ui
hard way using c# / server api
Semi-hard way using REST api
The simple way is to use the edit ui. You can see an example in the replace-dialog, there is a copy button there. This would open the edit UI with an existing item, but tell it it's a copy, so on save it would create a new one.
Combine this with a prefill or something and I think you would be good to go.
The second way is using the App.Data.Create - your code looks fairly good. I assume it also works and you were just wondering if there was a 1-liner - or am I mistaken?
The last way is using JS REST. Basically write some JS that gets an item, changes the object (resets the id) and posts it back to the endpoint for saving.
Just stumbled upon situation where I needed to create entity and set its field value, which has type of another entity. If that's your question #1, you need to add there EntityGuid.
fields.Add(attr.Key, attr.EntityGuid);. That should bind one entity to another one.
And no, I didn't stumble upon better way to copy entity then just to create a new one. At least so far.
The saga of trying to chop flat files up into useable bits continues!
You may see from my other questions that I am trying to wrangle some flat file data into various bits using C# transformer in SSIS. The current challenge is trying to turn a selection of rows with one column into one row with many columns.
A friend has very kindly tipped me off to use List and then to somehow loop through that in the PostExecute().
The main problem is that I do not know how to loop through and create a row to add to the Output Buffer programatically - there might be a variable number of fields listed in the flat file, there is no consistency. For now, I have allowed for 100 outputs and called these pos1, pos2, etc.
What I would really like to do is count everything in my list, and loop through that many times, incrementing the numbers accordingly - i.e. fieldlist[0] goes to OutputBuffer.pos1, fieldlist[1] goes to OutputBuffer.pos2, and if there is nothing after this then nothing is put in pos3 to pos100.
The secondary problem is that I can't even test that my list and writing to an output table is working by specifically using OutputBuffer in PostExecute, never mind working out a loop.
The file has all sorts in it, but the list of fields is handily contained between START-OF-FIELDS and END-OF-FIELDS, so I have used the same logic as before to only process the rows in the middle of those.
bool passedSOF;
bool passedEOF;
List<string> fieldlist = new List<string>();
public override void PostExecute()
{
base.PostExecute();
OutputBuffer.AddRow();
OutputBuffer.field1=fieldlist[0];
OutputBuffer.field2=fieldlist[1];
}
public override void Input_ProcessInputRow(InputBuffer Row)
{
if (Row.RawData.Contains("END-OF-FIELDS"))
{
passedEOF = true;
OutputBuffer.SetEndOfRowset();
}
if (passedSOF && !passedEOF)
{
fieldlist.Add(Row.RawData);
}
if(Row.RawData.Contains("START-OF-FIELDS"))
{
passedSOF = true;
}
}
I have nothing underlined in red, but when I try to run this I get an error message about PostExecute() and "object reference not set to an instance of an object", which I thought meant something contained a null where it shouldn't, but in my test file I have more than two fields between START and END markers.
So first of all, what am I doing wrong in the example above, and secondly, how do I do this in a proper loop? There are only 100 possible outputs right now, but this could increase over time.
"Post execute" It's named that for a reason.
The execution of your data flow has ended and this method is for cleanup or anything that needs to happen after execution - like modification of SSIS variables. The buffers have gone away, there's no way to do interact with the contents of the buffers at this point.
As for the rest of your problem statement... it needs focus
So once again I have misunderstood a basic concept - PostExecute cannot be used to write out in the way I was trying. As people have pointed out, there is no way to do anything with the buffer contents here.
I cannot take credit for this answer, as again someone smarter than me came to the rescue, but I have got permission from them to post the code in case it is useful to anyone. I hope I have explained this OK, as I only just understand it myself and am very much learning as I go along.
First of all, make sure to have the following in your namespace:
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
These are going to be used to get properties for the Output Buffer and to allow me to output the first item in the list to pos_1, the second to pos_2, etc.
As usual I have two boolean variables to determine if I have passed the row which indicates the rows of data I want have started or ended, and I have my List.
bool passedSOF;
bool passedEOF;
List<string> fieldlist = new List<string>();
Here is where it is different - as I have something which indicates I am done processing my rows, which is the row containing END-OF-FIELDS, when I hit that point, I should be writing out my collected List to my output buffer. The aim is to take all of the multiple rows containing field names, and turn that into a single row with multiple columns, with the field names populated across those columns in the row order they appeared.
if (Row.RawData.Contains("END-OF-FIELDS"))
{
passedEOF = true;
//IF WE HAVE GOT TO THIS POINT, WE HAVE ALL THE DATA IN OUR LIST NOW
OutputBuffer.AddRow();
var fields = typeof(OutputBuffer).GetProperties();
//SET UP AND INITIALISE A VARIABLE TO HOLD THE ROW NUMBER COUNT
int rowNumber = 0;
foreach (var fieldName in fieldList)
{
//ADD ONE TO THE CURRENT VALUE OF rowNumber
rowNumber++;
//MATCH THE ROW NUMBER TO THE OUTPUT FIELD NAME
PropertyInfo field = fields.FirstOrDefault(x = > x.Name == string.Format("pos{0}", rowNumber));
if (field != null)
{
field.SetValue(OutputBuffer, fieldName);
}
}
OutputBuffer.SetEndOfRowset();
}
if (passedSOF && !passedEOF)
{
this.fieldList.Add(Row.RawData);
}
if (Row.RawData.Contains("START-OF-FIELDS"))
{
passedSOF = true;
}
So instead of having something like this:
START-OF-FIELDS
FRUIT
DAIRY
STARCHES
END-OF-FIELDS
I have the output:
pos_1 | pos_2 | pos_3
FRUIT | DAIRY | STARCHES
So I can build a position key table to show which field will appear in which order in the current monthly file, and now I am looking forward into getting myself into more trouble splitting the actual data rows out into another table :)
I have a listview control that is filled with returned records from a SQL Statement. The fields may be something like:
SSN------|NAME|DATE----|TIME--|SYS
111222333|Bell|20140130|121507|P
123456789|John|20140225|135000|P
123456789|John|20140225|135002|N
The "duplicates" are generated from a ChangeLog, such as a change of address. Due to bad database design I have no control over however, an address change will create 2 records if a member happens to be a member of both SYS.
What would be the best way to go through each record in my listview, find duplicate values of SSN & DATE (There can be a record generated for both SYS if person is a member of both), and remove the duplicate value with the lower TIME value?
I'm trying to do a code-based solution instead of SQL because the true SQL statement is already highly complex and this application needs to only be maintained until October.
For this, I've assumed you have some class with these record's properties exposed with easy access like SSN and Time, I've also assumed they were both strings. In the code below I refer to this object as Record.
HINT: You might instead want to be removing items with the SYS flag set to False instead of judging it on time (Probably doesn't make a difference) .
I did not used any lambda fun on purpose to try to keep this simple and easy to read.
Call this code every time you load items into the ListView.... it would actually be a better idea to sanitize that list before you load it into the ListView, but the below code is a solution to your question based on the available info.
//Turn the ListView's ItemCollection into an easy to use List<Record>
List<Record> records = myListView.Items.OfType<Record>().ToList();
//Grab records with duplicate SSNs but with lower Time values
List<Record> recordsToRemove = new List<Record>();
foreach (var record in records)
{
foreach (var r in records)
{
if (record.SSN == r.SSN && record != r)
{
if (int.Parse(r.Time) > int.Parse(record.Time))
recordsToRemove.Add(record);
else
recordsToRemove.Add(r);
}
}
}
//Now actually remove the items from the ListView
foreach (var record in recordsToRemove)
{
myListView.Items.Remove(record);
}
So I have 70 "nodes" which are all textboxes in WPF and I'm trying to change the value in the textbox from a function call.
I have a function called:
private void changeNode(int row, int column, int cost)
{
int nodeNumber= row * 10 + column;
call node"nodeNumber".Text = Convert.String(cost);
//example node0.Text = Convert.String(cost);
}
I determine what node I want to change then call nodeX.Text to change it however I want X to be a variable that I can rather than having to create 70 cases where I call the appropriate textbox.
I saw a couple of ways of doing this with reflection however it seemed to only work if the function had no parameters and also was within the function not a textbox in XAML.
Let me know if there is a simple way to convert say a string "node37" to call node37.Text = cost or something like that.
Sounds like your approach is wrong. Why do you have a set of strings which represent the names of the textboxes? You should instead have in-memory references to TextBox objects. If you have more than one, and you don't know how many there will be, then use an array of TextBox objects instead. You can index into the array with the number that represents the textbox you're looking to interact with.
Avoid the use of reflection, it is completely unnecessary here.
I assume you have put names for all your textboxes (you can do this dynamically if you haven't). Then you can use the answers for this question to find the appropriate control by name.
Are all your textboxes children of the same canvas or other control? Loop through the children and add the controls to a dictionary. Parse the name to get the number and use that as the key.
It is always better to use List when you are dealing with Data. Create an ObservableCollection with the DataObjects which you want to load, and now deal with the Data object rather than actual Controls.
In WPF, if you follow the rules, you should not point to the actual object. Check the sample application here :
http://www.abhisheksur.com/2010/08/woring-with-icollectionviewsource-in.html
I think you will get the approach.
I created an object called Participant.
Now I want to have an array of my Participant objects so that I could show them in a datagrid.
Here are the codes I tried (for better understanding of the problem, I removed the loops and datagrid codes):
Participant[] list = new Participant[count];
Participant one = new Participant(name, address);
Participant two = new Participant(name2, address2);
list[0] = one;
list[1] = two;
However, when I get values of one participant like through a messagebox in this manner,
MessageBox.Show(list[0].getName());
all it reflects are the data of participant two. Same is true if I have 3 objects, all it reflects is the data last sent into the array.
I know it is possible to have array of objects so there must be something I'm doing wrong. Or is there a better way to do this?
With the code as presented, the only way I can think of causing that is if the backig field (in Participant) was declared "static". If so, remove the "static".
Otherwise; does the actual code do a "new" for the two objects? Or does it overwrite an object after adding it to the array? (which means you have the same object twice in the array).
I would expect ReferenceEquals(list[0], list[1]) to be false in a sane world - can you test this and let us know?
Final thought; is there a "foreach" in the real code? It could be the infamous captured variable problem...
If you are using a loop to populate your array, be sure you use the loop index as the index of the array when you assign the paticipant.
Debugging is an underrated skill... Set a breakpoint on the line where you create the array and add list as a watch, and expand it so you see the contents. Step through your code and hover over the parameters as you're creating the Participants to see the values being passed. Step over the statemens that add them to the list and verify in your watch that the correct item and values are in the array each time and that the existing values haven't changed.