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.
}
Related
I am currently struggling to accept a list of objects from FormData in ASP.NET Core.
The project looks like this:
I have a class called Stavka (English: Item).
public class Stavka
{
public string naziv { get; set; }
public double cenaPoJedinici { get; set; }
public string jedinicaMere { get; set; }
public int kolicina { get; set; }
public Stavka(string naziv, double cenaPoJedinici, string jedinicaMere, int kolicina)
{
this.naziv = naziv;
this.cenaPoJedinici = cenaPoJedinici;
this.jedinicaMere = jedinicaMere;
this.kolicina = kolicina;
}
public Stavka()
{
}
}
I have a class called Faktura (English: Bill) which has a variable called Stavke (English: Items) that is a list containing the Stavka objects.
public class Faktura
{
public int Id { get; set; }
public string pibStart { get; set; }
public string pibEnd { get; set; }
public DateTime datumGen { get; set; }
public DateTime datumRok { get; set; }
public List<Stavka> stavke { get; set;}
public double cena { get; set; }
public string tip { get; set; }
public Faktura(int id, string pibStart, string pibEnd, DateTime datumGen, DateTime datumRok, List<Stavka> stavke, string tip)
{
Id = id;
this.pibStart = pibStart;
this.pibEnd = pibEnd;
this.datumGen = datumGen;
this.datumRok = datumRok;
this.stavke = stavke;
this.tip = tip;
double sumCena = 0;
foreach(Stavka s in stavke)
{
sumCena += s.kolicina * s.cenaPoJedinici;
}
this.cena = sumCena;
}
public Faktura()
{
}
I want to create a new Faktura object and add it to a list within my Controller. I tried to do this with the following code:
[HttpPost("dodajFakturu")]
public IActionResult dodajFakturu([FromForm]string pibStart, [FromForm]string pibEnd,[FromForm]DateTime datumStart, [FromForm]DateTime datumEnd,[FromForm]List<Stavka> stavkeLis, [FromForm]string tip)
{
int id = lst.OrderByDescending(p => p.Id).First().Id + 1;
Faktura f = new Faktura(id, pibStart,pibEnd, datumStart,datumEnd,stavkeLis,tip);
lst.Add(f);
return Ok(SveFakture());
}
And yet, when i post the request (in Swagger/Postman), the variable stavkeLis (which accepts the JSON array) is always empty:
This is certainly because i fundamentally misunderstood the way in which NET Core accepts these variables.
Is there some other way to send a list of objects through form data?
this way you have is currect, but if its not maybe because simple code problem but way that you right the code can be better or you can say develop your code as Below:
// StavkaBody => I Mean All Body In One Json
public async Task<IActionResult> MethodName([FromForm] string
StavkaBody)
{
YourObjectType object = new YourObjectType();
// this will be Populate All Json To Single object And
// You dont Need To Add some Constructors For Done this
JsonConvert.PopulateObject(StavkaBody, objec);
// Example Usage
Console.WriteLine(object.Name);
}
in Here I`ve Used The Newtonsoft.Json For this And Its Make Your Model So Much Simpler.
I Hope Its Helps
I have three classes:
public class M2ArticleMain
{
public int Id { get; set; }
public List<M2ArticleAttributeWeb> Attribut_Web { get; set; }
}
public class M2ArticleAttributeWeb
{
public int Web_Id { get; set; }
public M2ArticleTmpMainSkus Variants { get; set; }
}
public class M2ArticleTmpMainSkus
{
public DateTime TimeAdded { get; set; }
public List<string> Skus { get; set; }
}
And I have two Lists in my code like this:
List<M2ArticleMain> data = new List<M2ArticleMain>();
List<M2ArticleAttributeWeb> attb = new List<M2ArticleAttributeWeb>();
In some part of my code firstly I (from foreach loop) add data to attb list where I add only only some data (because I don't have all data at this point), like this:
...
attb.Add(new M2ArticleAttributeWeb
{
Web_id = item.Id, //(item is from foreach loop)
Variants = null //this is **importat**, I left null for later to add it
});
Next, after I fill attb, I add all this to data list:
...
data.Add(new M2ArticleMain
{
Id = item.Id_Pk, //this is also from foreach loop,
Attribut_Web = attb //now in this part I have only data for Web_id and not Variants
}
Now my question is How to Add items later to data list to object Variants?
Something like this:
data.AddRange( "how to point to Variants" = some data);
The M2ArticleAttributeWeb type holding your Variants property is the member of a collection. That is, there are potentially many of them. You can reference an individual Variants property like this:
data[0].Attribut_Web[0].Variants
But you need to know which items you want to add map to which data and Attribut_Web indexes/objects in order to assign them properly. That probably means another loop, or even a nested loop. That is, you can see all of your Variants properties in a loop like this:
foreach(var main in data)
{
foreach(var attrw in main)
{
var v = attrw.Variants;
// do something with v
Console.WriteLine(v);
// **OR**
attrw.Variants = // assign some object
}
}
It's also much better practice to create your collection properties with the object, and then give them private set attributes:
public class M2ArticleMain
{
public int Id { get; set; }
public List<M2ArticleAttributeWeb> Attribut_Web { get; private set; } = new List<M2ArticleAttributeWeb>();
}
public class M2ArticleAttributeWeb
{
public int Web_Id { get; set; }
public M2ArticleTmpMainSkus Variants { get; set; }
}
public class M2ArticleTmpMainSkus
{
public DateTime TimeAdded { get; set; }
public List<string> Skus { get; private set; } = new List<string>();
}
Now instead of assigning Attribut_Web = attb, you would need to .Add() to the existing List.
I want to return a list of links to a web page when it loads. Right now I have a model called SsoLink.cs bound to the page. I would like to return a list, so I have created another model called SsoLinks.cs that has a List. In my helper function, I keep getting "object not set to an instance of an object".
SsoLink.cs
public class SsoLink
{
public enum TypesOfLinks
{
[Display(Name="Please Select a Type")]
Types,
Collaboration,
[Display(Name="Backups & Storage")]
Backups_Storage,
Development,
[Display(Name="Cloud Services")]
Cloud_Services,
[Display(Name="Human Resources")]
Human_Resources,
Analytics
}
public string Id { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Owner { get; set; }
public string OwnerEmail { get; set; }
public string LinkDescription { get; set; }
public TypesOfLinks LinkType { get; set; }
}
SsoLinks.cs
public class SsoLinks
{
public List<SsoLink> Links {get; set;}
}
GetLinksHelper.cs
public partial class SsoLinkHelper
{
public static SsoLinks GetLinks()
{
var ssoList = new SsoLinks();
try
{
//search the index for all sso entries
var searchResponse = _client.Search<SsoLink>(s => s
.Index(_ssoLinkIndex)
.Size(500)
.Query(q => q
.MatchAll()
)
);
if (searchResponse.Documents.Count == 0)
{
return ssoList;
}
ssoList.Links.AddRange(searchResponse.Hits.Select(hit => new SsoLink() {Id = hit.Source.Id, Name = hit.Source.Name, Url = hit.Source.Url, Owner = hit.Source.Owner}));
return ssoList;
}
catch (Exception e)
{
Log.Error(e, "Web.Helpers.SsoLinkHelper.GetLinks");
return ssoList;
}
}
}
While debugging, It is failing at SsoLinks.Links.AddRange(etc). How can I add a new SsoLink to the ssoList for every item found in my query?
Edit: Here is a screenshot of the error while debugging.
The null reference exception looks like it comes from ssoList.Links being null when calling AddRange on it, so it needs to be initialized to a new instance of List<SsoLink> before calling AddRange().
Russ's answer led me down the right path, I ended up just needing to change my view to:
#model List<SharedModels.Models.SsoLink>
rather than
#model SharedModels.Models.SsoLink
and do away with the SsoLinks model.
I have created a base class as "Common" there are many properties such as pageno,pagesize,search,etc which will use in all classes for entire project(must require).
There is other class as "Area" which extends "Common" class.
All properties are automatic get and set.
Here the problem is,
I have created web api.It returned object of Area class.
So here client received all properties of area and common.But I need specific properties to response.
Means I just need two properties of Area i.t AreaId,AreaName
This requirement for retuned data in different format like JSON and XML.I did with linq it gives specific properties Which I need exactly. But It is anonymous type data. Not strongly object.
following sample of my code
public class Common
{
public int CaseNo { get; set; }
public int? RET_ID { get; set; }
public string MSGSTATUS { get; set; }
public string MSG { get; set; }
public int? LoginId { get; set; }
}
public class Area : Common
{
public int AreaId { get; set; }
public string AreaName { get; set; }
public string PinCode{ get; set; }
}
/Web api code/
public IHttpActionResult GetAreaById(int AreaId, int LoginId)
{
try
{
AreaDAL objDal = new AreaDAL();
Area objBo = new Area();
objBo = objDal.EditArea(AreaId, LoginId);
if (objBo != null)
{
/*Not working for xml returned data(work for json).anonymous type data*/
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, new Area { AreaId = objBo.AreaId, AreaName = objBo.AreaName }));
/*working for json and xml */
/*But it retuned all properties of Area and common*/
/*Needed as AreaId and AreaName*/
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, objBo));
}
}
Introduce an intermediate class (AreaInfo) and pull AreaId and AreaName members up:
public class AreaInfo : Common
{
public int AreaId { get; set; }
public string AreaName { get; set; }
}
public class Area : AreaInfo
{
public string PinCode{ get; set; }
}
//...
public IHttpActionResult GetAreaById(int AreaId, int LoginId)
{
try
{
AreaDAL objDal = new AreaDAL();
Area objBo = new Area();
objBo = objDal.EditArea(AreaId, LoginId);
if (objBo != null)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, new AreaInfo { AreaId = objBo.AreaId, AreaName = objBo.AreaName }));
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, objBo));
}
}
edit: for hiding fields in the Common base class, you can:
1) Change their access modifier (e.g. to protected)
2) Mark them with attributes to be skipped on serialization like:
[XmlIgnore] for xml serialization
[JsonIgnore] for json serialization
3) Separate the class hierarchies (Common from AreaInfo<-Area) and use composition for when you need
extra fields in Common class.
e.g.
public class Common<T>
where T: class
{
//... common fields here
public T Data {get;}
public Common(T data) => Data = data;
}
...
var area = new Common(new Area(){...});
//area.LoginId;
//area.Data.AreaId;
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();
}