I have this structure of classes:
public class L3Message
{
public int Number { get; set; }
public string MessageName { get; set; }
public string Device { get; set; }
public string Time { get; set; }
public string ScramblingCode { get; set; }
public List<Parameter> Parameters { get; set; }
public L3Message()
{
Parameters = new List<Parameter>();
}
}
public class Parameter
{
public int numOfWhitespaces { get; set; }
public string ParameterName { get; set; }
public string ParameterValue { get; set; }
public Parameter Parent { get; set; }
public List<Parameter> SubParameters { get; set; }
public Parameter()
{
SubParameters = new List<Parameter>();
}
}
So, as return type from one of my Methods I have List of L3Messages (List<L3Message>), and I need to map that to TreeView in WinForms (populate TreeView from that List).
EDIT:
Please notice that tree of my objects can be deeper than one level (becouse class Parameter have prop List < Parmaeter > (List of Parameter object, same structure as root parameter object)), so that means recursion or something like.
EDIT2:
Here is pic of tree, but this tree is created from text file base on whitespaces, so here is all Parameters, in my tree I need only one from List of L3Message objects.
http://imageshack.us/photo/my-images/803/treeviewmessage.png/
EDIT3:
I'm sure that my TreeView need to be something like this:
L3Message.Number: L3Message.MessageName
+L3Message.Time
+L3Message.Device
+L3Message.ScramblingCode
+L3Message.Parameters[0]
++Parameter.ParamaeterName: Parameter.ParameterValue
++ (same as above)
L3Message.Number: L3Message.MessageName
+L3Message.Time
+L3Message.Device
+L3Message.ScramblingCode
+L3Message.Parameters[0]
++Parameter.ParamaeterName: Parameter.ParameterValue (in this occasion Value is null )
+++SubParameter.ParameterName: SubParameter.ParameterValue
Something like that
If possible, I would like to that in separate thread.
How can I achieve that?
Of course it is possible. Now it depends how you want your TreeView to be structured. Then you just need to create TreeNode objects and add them to the TreeView. See this small tutorial: http://www.dotnetperls.com/treeview
If you are going to do this on a different thread, you will need to update the GUI by forwarding the updates to the GUI thread using BeginInvoke:
TreeNode node = new TreeNode("node");
L3Message msg = new L3Message();
node.Tag = msg;
treeView.BeginInvoke(
(Action)(() =>
{
treeView.Nodes.Add(node);
}));
Notice that the TreeNode needs to be created with a string representing the name and then you can add the object it points to using the Tag property.
I managed to solve this, but I think that is not optimize and there is no separate thread.
If anyone can modify my code to perform better and add separate thread?
SOLUTION:
foreach (L3Message message in por)
{
treeViewMessages.Nodes.Add(message.Number + ": " + message.MessageName);
treeViewMessages.Nodes.Add("Time: " + message.Time);
treeViewMessages.Nodes.Add("MS: " + message.Device);
treeViewMessages.Nodes.Add("Scrambling Code: " + message.ScramblingCode);
foreach (Parameter param in message.Parameters)
{
TreeNode tnRootParam = new TreeNode();
//tnRootParam.Nodes.Add(param.ParameterName + ": " + param.ParameterValue);
if (param.SubParameters.Count != 0)
{
CreateTreeNodes(param, tnRootParam);
tnRootParam.Text = param.ParameterName;
treeViewMessages.Nodes.Add(tnRootParam);
}
else
{
tnRootParam.Text = param.ParameterName + ": " + param.ParameterValue;
treeViewMessages.Nodes.Add(tnRootParam);
}
}
treeViewMessages.Nodes.Add("---------------------------------------------------------------------");
}
private void CreateTreeNodes(Parameter parameter, TreeNode tnRootParam)
{
if (parameter.SubParameters.Count == 0)
{
tnRootParam.Nodes.Add(parameter.ParameterName + ": " + parameter.ParameterValue);
}
else
{
foreach (Parameter subparam in parameter.SubParameters)
{
CreateTreeNodes(subparam, tnRootParam);
}
}
}
Related
With the help of everyone in a very short time. The problem got solved by overriding the toString Method.
I have a problem with the following: (solved)
public class CryptoApiResponse
{
[DeserializeAs(Name = "ticker")]
public List<CryptoAttributes> CryptoCurrency { get; set; }
public override string ToString()
{
return $"Currency:{CryptoCurrency[0].Currency} " +
$"PriceFiat:{CryptoCurrency[0].PriceFiat} " +
$"Fiat:{CryptoCurrency[0].TargetFiat}";
}
}
public class CryptoAttributes
{
[DeserializeAs(Name = "base")]
public string Currency { get; set; }
[DeserializeAs(Name = "target")]
public string TargetFiat { get; set; }
[DeserializeAs(Name = "price")]
public string PriceFiat { get; set; }
}
And I want to access the following:
public void Display<CryptoApiResponse>(List<CryptoApiResponse> apiList)
{
if (apiList != null)
{
foreach (CryptoApiResponse cryptoCurrency in apiList)
{
Console.WriteLine(cryptoCurrency.ToString());
}
}
Console.ReadLine();
}
Console.WriteLine(obj);
// this means more or less the following
Console.WriteLine(obj.ToString());
// this means you should override the ToString() method
// or to make a custom string
You're iterating through a List, and in each crypto there exist a sub-list List. In short you get List>.
When you foreach this List, you may need to use a second foreach to iterate the values in the Sub list to reach your property.
foreach (var crypt in crypto)
{
foreach (var basedata in crypt.Ticker)
{
Console.WriteLine($"Currency:{basedata.Currency} Price: {basedata.Price} Target: {basedata.Target}");
}
}
If you keep the naming of the API you linked and differentiate between lists ans single objects names it will be easier to understand what is the problem. The classes should look something like this (pay attention to the difference between Ticker and Tickers
public class Crypto
{
public List<Ticker> Tickers { get; set; }
}
public class Ticker
{
public string Currency { get; set; }
public string Target { get; set; }
public string Price { get; set; }
}
The parameter crypto (should be cryptos) in Display is a list and Tickers is a list, so you need nested loop. You should also remove the Crypto parameter from the methos signature as it hides the Crypto class
public void Display(List<Crypto> cryptos)
{
foreach (Crypto crypto in cryptos)
{
foreach (Ticker ticker in crypto.Tickers)
{
Console.WriteLine(ticker);
}
}
}
Or if you would like to use partial Linq
public void Display(List<Crypto> cryptos)
{
foreach (Ticker ticker in cryptos.SelectMany(crypto => crypto.Tickers))
{
Console.WriteLine(ticker);
}
}
Could you try to use "Crypto" instead of "var" when looping? I mean do it like this. I remeber the version before VS2015 (may be VS2010), the type of variable will be treated as object if we use "var".
public void Display<Crypto>(List<Crypto> crypto)
{
if (crypto != null)
{
// Currency, Target and Price
foreach (***Crypto*** ticker in crypto)
{
Console.WriteLine(ticker); // ticker Type Crypo
// ticker.Ticker
}
}
Console.ReadLine();
}
I'm working on creating a windows form plugin to create Layers from the user selected items on my windows form.
I am reading a list of Layers in to a list box(lbGetLayers), a list of modifiers in to another listbox(lbModifyer) from two different csv files. Additionally, I have created two classes to hold the layer, modifier objects.
Goal: is to create a new layer with the correct Name, Color, Line Style, and Line Weight based on user selected items.
Issue:
I am trying to write a function to build the logic before creating the layer to satisfy the below two conditions:
1) Layer- Will have a color, line style, and line weight. Let the user pick 1 or more. If the user picks more than 1 then the app will create all layers selected.
2)Modifier – will override the color, line style, and line weight. The user can pick 0 or 1.
3)Status(Edited) - will again override the color, line style and the line weight. The user can pick 0 or 1.
I came up with the a function which is not appropriate to satisfy these conditions.
I'd really appreciate if somebody could help me solving this problem.
Thanks!!
BuildLayers:
public Intellayer Buildlayer()
{
//can select Layer - 1 or more
//Get Selected Layer Object - color, line style & line weight
foreach(Intellayer SelectedLayer in lbGetLayers.Items)
{
foreach (Modifyer SelectedModifyer in lbModifyer.Items)
{
if(lbGetLayers.SelectedItems.Count > 1 || lbModifyer.SelectedItems.Count <= 1)
System.Diagnostics.Debug.WriteLine(SelectedLayer.layername + "-" + SelectedModifyer.name);
}
}
Class:
public class layer
{
public string disciplane { get; set; }
public string layername { get; set; }
public string Linetype { get; set; }
public int? Layercolor { get; set; }
public string Description { get; set; }
public string Lineweight { get; set; }
public override string ToString()
{
return layername;
}
}
public class Modifyer
{
public string discipline { get; set; }
public string name { get; set; }
public int? color { get; set; }
public string Linetype {get;set;}
public string Lineweight { get; set; }
public string Description { get; set; }
public override string ToString()
{
return name;
}
}
Edited:
BuildLayers:
public List<layer> Buildlayers()
{
//Build selected layers
List<layer> Getselectedlayers = null;//list of selected layers
if (lbGetLayers.SelectedItems.Count >= 1)
{
Getselectedlayers = new List<layer>();
Getselectedlayers.AddRange(lbGetLayers.SelectedItems.Cast<layer>());
foreach (layer lname in Getselectedlayers)
{
lbGetLayers.SelectedItems.Cast<layer>();
System.Diagnostics.Debug.WriteLine(lname.Linetype + "," + lname.Lineweight + "," + lname.Layercolor);
}
if (lbModifyer.SelectedItems.Count == 1)
{
Modifyer modifyer = (Modifyer)lbModifyer.SelectedItem;
foreach (layer lname in Getselectedlayers)
{
lname.Override(modifyer);//Override with Modifyers
}
}
if(lbStatus.SelectedItems.Count == 1)
{
Status status = (Status)lbStatus.SelectedItem;
foreach (layer lname in Getselectedlayers)
{
lname.Override(status);//Override with Status
}
}
}
return Getselectedlayers;//return list of selected layers
}
}
}
Class:
public class layer
{
public string disciplane { get; set; }
public string layername { get; set; }
public string Linetype { get; set; }
public int? Layercolor { get; set; }
public string Description { get; set; }
public string Lineweight { get; set; }
public layer Override(Modifyer modifyer)
{
layer newLayer = new layer();
newLayer.layername = this.layername;
newLayer.Layercolor = modifyer.color;
newLayer.Linetype = modifyer.Linetype;
newLayer.Lineweight = modifyer.Lineweight;
return newLayer;
}
public layer Override(Status status)
{
layer newlayer = new layer();
newlayer.layername = this.layername;
newlayer.Layercolor = status.color;
newlayer.Linetype = status.Linetype;
newlayer.Lineweight = status.Lineweight;
return newlayer;
}
public override string ToString()
{
return layername;
}
}
You seem to have most of the meat there, but there are a couple issues in the code you posted aside from the logic inside the Buildlayer() method.
Let's start with the constructor. The point of the constructor is to initialize the form. This is also a good place to assign data to your controls. Here, the user has not had a chance to select any items as the forms is not yet visible. This is where you should be parsing your CSV file and assigning the resulting objects to your respective listboxes.
public LayerCreationTool()
{
InitializeComponent();
fillListBoxes();
}
private void fillListBoxes()
{
//get layers from CSV here and put them into ListBox
lbGetLayers.Items.AddRange(getLayersFromCSV().ToArray());
lbModifyer.Items.AddRange(getModifiersFromCSV().ToArray());
}
private List<layer> getLayersFromCSV()
{
List<layer> layers = new List<layer>();
//...Do your parsing here;
return layers;
}
private List<Modifier> getModifiersFromCSV()
{
List<Modifier> modifiers = new List<Modifier>();
//...Do your parsing here;
return modifiers;
}
I also added a method Override() to your layer class. This will allow you to easily utilize your modifier.
public class layer
{
public string layername { get; set; }
public string Linetype { get; set; }
public int? Layercolor { get; set; }
public string Lineweight { get; set; }
public layer Override(Modifier modifier)
{
layer newLayer = new layer();
newLayer.layername = this.layername;
newLayer.Layercolor = modifier.color;
newLayer.Linetype = modifier.Linetype;
newLayer.Lineweight = modifier.Lineweight;
return newLayer;
}
public override string ToString()
{
return layername;
}
}
Now that you have a functional form, you need a way for the user to say "Go". I've taken the liberty of adding a button to the form, and in the click event of the button is where you should be creating your layers as per your logic. Also, Since you want to be returning more than one layer, Buildlayers() should return List<layer> rather than layer.
The idea for the logic is simple: if a modifier is NOT selected, then add all the selected layers to add to AutoCad. If a modifier IS selected, then use the Override() method to grab and modify all selected items one at a time.
private void btnImport_Click(object sender, EventArgs e)
{
List<layer> layersToAddToAutoCad = Buildlayers();
//now use your these layers to add to AutoCad...
}
//You need to return a List of layers that you then use
//to add layers to AutoCad
public List<layer> Buildlayers()
{
List<layer> ret = null;
if(lbGetLayers.SelectedItems.Count > 0)
{
ret = new List<layer>();
//if no modifier selected, great, just grab all the selected layers
if (lbModifyer.SelectedItems.Count == 0)
{
ret.AddRange(lbGetLayers.SelectedItems.Cast<layer>());
}
else
{
Modifier modifier = (Modifier)lbModifyer.SelectedItem;
foreach (layer layerToAdd in lbGetLayers.SelectedItems)
{
ret.Add(layerToAdd.Override(modifier));
}
}
}
return ret;//method must return something.
}
I want to make a program that lists recipes, their ingredients and only ingredients on a separate page.
I was thinking of creating classes "Ingredient" and "Recipe". The "Recipe" class will have a name and description properties and a Dictionary<Ingredient, int> property. I was thinking of filling the dictionary with "ingredient" classes and the amount they are needed in, for example let's say I create an instance of the "Recipe" class and name it "Pancakes". I will add a new Ingredient instance, named "Milk" to the dictionary with the amount 100 (for example) and do the same for "eggs" and so forth.
Is this the correct way to go about such a thing, as I will want to create references or links to the ingredients themselves on the "ingredients" page?
The way you have described will work correctly. However, a common solution for what you have described is the decorator pattern. The decorator pattern is used for creating dynamic objects.
https://www.youtube.com/watch?v=j40kRwSm4VE
This example is using pizza and toppings but it's essentially the same concept.
Something like this would work:
public enum UnitOfMeasurement
{
Grams,
Milliliters
}
public class Ingredient
{
public UnitOfMeasurement UnitOfMeasurement { get; set; }
public decimal Unit { get; set; }
public string Name { get; set; }
}
public class Recipe
{
public string Description { get; set; }
public List<Ingredient> Ingredients { get; set; }
public List<string> RecipeSteps { get; set; }
}
I might be tempted to create a class or some more complex object for recipe steps as well but that largely depends on what you want to do with this.
I was asked to do something like this recently in an interview, had to put in a recipe and then print it out by overriding the ToString() method. Obviously it can be cleaned up a lot, but the general idea is there.
came up with this code:
using System;
namespace cSHARP
{
class Program
{
static void Main(string[] args)
{
Recipe myRecipe = new Recipe();
Ingredient myIngredient = new Ingredient();
Ingredient myIngredient2 = new Ingredient();
myRecipe.Name = "Fish and Chips";
myIngredient.Name = "Fish";
myIngredient.Amount = 3;
myIngredient.AmountType = "pieces";
myIngredient2.Name = "Chips";
myIngredient2.Amount = 1;
myIngredient2.AmountType = "regular serving";
myRecipe.Ingredients = new Ingredient[2];
myRecipe.Ingredients[0] = myIngredient;
myRecipe.Ingredients[1] = myIngredient2;
Console.WriteLine(myRecipe.ToString());
}
}
public class Recipe
{
public string Name { get; set; }
public Ingredient[] Ingredients { get; set; }
public override string ToString()
{
string retVal = "";
retVal = retVal + "\n Recipe Name is " + this.Name;
retVal = retVal + "\n Ingredient one is "
+ this.Ingredients[0].Amount.ToString() + " "
+ this.Ingredients[0].AmountType.ToString() + " of "
+ this.Ingredients[0].Name;
retVal = retVal + "\n Ingredient two is "
+ this.Ingredients[1].Amount.ToString() + " "
+ this.Ingredients[1].AmountType.ToString() + " of "
+ this.Ingredients[1].Name;
return (retVal);
}
}
public class Ingredient
{
public string Name { get; set; }
public int Amount { get; set; }
public string AmountType { get; set; }
}
}
Hi guys i want to ask that i have a Class with properties like following:
public class VLANSPropertyClass
{
public string vname { get; set; }
public int S_No { get; set; }
public string vid { get; set; }
public string ip { get; set; }
public string vports { get; set; }
}
I created an ObservableCollection as follows:
public ObservableCollection<VLANSPropertyClass> vlan { get; set; }
vlan = new ObservableCollection<VLANSPropertyClass>();
I am adding all these values in a datagrid:
void AddVlans()
{
var serial = new VLANSPropertyClass();
serial.S_No = vlan.Count + 1;
Console.WriteLine(serial.S_No);
serial.vname = VlanName;
Console.WriteLine(serial.vname);
serial.vid = VlanID;
Console.WriteLine(serial.vid);
serial.ip = VlanIP1 + "." + VlanIP2 + "." + VlanIP3 + "." + VlanIP4;
Console.WriteLine(serial.ip);
serial.vports = SelectedVlanPort;
vlan.Add(serial);
}
The display looks like following image:
Now i want go through each row and read its values.I tried following but didnt work
foreach(VLANSPropertyClass v in vlan)
{
Console.WriteLine(v);
Console.WriteLine();
}
Kindly tell me the possible way of reading values from ObservableCollection/Datagrid.Any help would be highly appreciable.
You can change your class to this...
public class VLANSPropertyClass
{
public string vname { get; set; }
public int S_No { get; set; }
public string vid { get; set; }
public string ip { get; set; }
public string vports { get; set; }
public override string ToString()
{
return String.Format("Name: {0}, Serial {1}", vname, S_No);
}
}
This change includes an override to the ToString method. It will be called whenever the framework needs a string representation of your class.
ToString is the major formatting method in the .NET Framework. It
converts an object to its string representation so that it is suitable
for display. (For information about formatting support in the .NET
Framework, see Formatting Types.)
source: http://msdn.microsoft.com/en-us/library/system.object.tostring.aspx
Using an override to ToString will let you do this Console.WriteLine(v); with expected results.
When you loop through an ObservableCollection<>, accessing it through index returns a complete instance/item of the collection in form of the string, you now need to reference this string using index or property(in case its a user defined type(class)) in order to access the real content, in my case i am doing this to access temp property of an item of the collection mess.
mess[mj_key][mn_key][0].Temp.ToString()
here i have 3 dimensions, avoid it for now, just understand that 0 index returns string object, i then access temperature using .Temp
Hope it Helps!
I've seen a couple questions about this, and done some research.
My understanding is that when you run a foreach on IEnumerable: if T is a Reference Type (e.g. Class) you should be able to modify properties of the object from within the loop. If T is a value type (e.g. Struct) this would not work since the iteration variable would be a local copy.
I am working on a Windows Store app with the following code:
My Class:
public class WebResult
{
public string Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string DisplayUrl { get; set; }
public string Url { get; set; }
public string TileColor
{
get
{
string[] colorArray = { "FFA200FF", "FFFF0097", "FF00ABA9", "FF8CBF26",
"FFA05000", "FFE671B8", "FFF09609", "FF1BA1E2", "FFE51400", "FF339933" };
Random random = new Random();
int num = random.Next(0, (colorArray.Length - 1));
return "#" + colorArray[num];
}
}
public string Keywords { get; set; }
}
The Code:
IEnumerable<WebResult> results = from r in doc.Descendants(xmlnsm + "properties")
select new WebResult
{
Id = r.Element(xmlns + "ID").Value,
Title = r.Element(xmlns + "Title").Value,
Description = r.Element(xmlns +
"Description").Value,
DisplayUrl = r.Element(xmlns +
"DisplayUrl").Value,
Url = r.Element(xmlns + "Url").Value,
Keywords = "Setting the keywords here"
};
foreach (WebResult result in results)
{
result.Keywords = "These, are, my, keywords";
}
if (control is GridView)
{
(control as GridView).ItemsSource = results;
}
Once the results get displayed the "Keywords" property is "Setting the keywords here". If I put a break point in the foreach loop I can see that the results object is not getting modified...
Any ideas as to what is going on? Am I just missing something obvious? Does IEnumerable behave differently in .NET For Windows Store Apps?
This is known as deferred execution; results is a query that is executed every time you iterate over it. In your case it's evaluated twice, once in the for loop, and a second time when it's databound.
You can verify this by doing something like this
var results2 = results.ToList();
foreach (WebResult result in results2)
{
result.Keywords = "These, are, my, keywords";
}
if (control is GridView)
{
(control as GridView).ItemsSource = results2;
}
You should see that your changes persisted.