My application's front end is a DataGrid whose contents are passed to an Excel-generating method.
The catch is that the DataGrid deals with 13 columns: 10 of them are fixed (i.e., passed to Excel) while each of the last 3 is optional.
public class GridModel
{
public string Item { get; set; }
public string ItemName { get; set; }
public double TotalHeight { get; set; }
public double AGLheight { get; set; }
public double Embedment { get; set; }
public string Shape { get; set; }
public double TipDiameter { get; set; }
public double BaseDiameter { get; set; }
public double Taper { get; set; }
public double ShearReaction { get; set; }
// The following are optional, in 8 combinations, from all present to all absent
public double Camber { get; set; }
public double Rake { get; set; }
public double Angle { get; set; }
}
Being a C# newbie, I am considering the different approaches.
How would you folks deal with this? The simplest idea that comes to mind is to add 3 flags to the model:
bool IsColumn1Present;
bool IsColumn2Present;
bool IsColumn3Present;
Another way would be to add a level to the hierarchy, so each of the 'special' columns contains its own embedded flag:
if (Camber.flag) add(Camber.value);
That said, I would like to have the ability to somehow remove those 3 properties, so any attempt to access them would result in an error or impossibility.
If such thing exists, I guess it would be called "Variant Properties".
TIA
Note: I have solved this already by the manipulation of the Visibility.Visible field at the GUI level. Gurus, however, tell us that this is a bad idea. Best practices dictate that this facility should be part of the Model.
You could use nullable properties:
public double? Camber { get; set; }
Then check them for a value in your business logic:
if (thing.Camber.HasValue)
{
DoSomething(thing.Camber.Value);
}
It sounds like this might be exactly what you're after, given your comment on "variant" properties.
More info: http://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx
Update: If you need to switch them off application-wide (as per your comment), you could either avoid setting the value in the first place when it's not wanted (this would be preferable as this is, as far as I'm concerned, business logic and doesn't belong in your dumb model classes) or extend this with a custom accessor:
private double? _camber;
public double? Camber
{
get
{
return ModelSettings.CamberEnabled
? _camber
: null;
}
set;
}
Then have some static/constant property somewhere:
public static class ModelSettings
{
public const bool CamberEnabled = true;
}
If the number of columns is constant (meaning the user can't add 'custom' columns), I would suggest a bit-field enum value like so:
[Flags]
public enum ColumnFlags
{
None = 0,
Camber = 0x1,
Rake = 0x2,
Angle = 0x4,
// Other optional columns here, keep them powers of 2!
}
Then in your Model class, keep a value such as:
public ColumnFlags ColumnFlags { get; set; }
Then you can use...
if(model.ColumnFlags.HasFlag(ColumnFlags.Camber))
{
// Do something here...
}
if(model.ColumnFlags.HasFlag(ColumnFlags.Rake))
{
// Do something here...
}
EDIT: Alternatively, you can use the Nullable<T> types to specify a "missing" or "empty" value.
Related
Hi I am using this function to show json in DataGridView but the problem is I have a list in the json file , this list doesn't display data in the grid
void show_data()
{
dataGrid.Columns.Clear();
dataGrid.DataSource = all_date;
}
my json file is as this
[{"Name":"350SC250-14","Fy":33.0,"GFy":false,"T":0.0713,"GT":false,"D":2.5,"Stud_D":1.5,"C":0.0,"B":3.5,"GB":false,"Manufacturer":"BIDDLE","CFS_File":"350SC250-14.cfss","Sub_SectionCount":0,"Sub_Section1":"","Sub_Section2":"","Sub_Section3":"","SectionType":3,"Configuration":0,"SectionParts":[{"Length":0.375,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":3.0,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":2.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":3.0,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.375,"Radius":0.0}]}]
my class is bellow
class dataForm
{
public string Name { get; set; }
public double Fy { get; set; }
public bool GFy { get; set; }
public double T { get; set; }
public bool GT { get; set; }
public double D { get; set; }
public double Stud_D { get; set; }
public double C { get; set; }
public double B { get; set; }
public bool GB { get; set; }
public string Manufacturer { get; set; }
public string CFS_File { get; set; }
public int Sub_SectionCount { get; set; }
public string Sub_Section1 { get; set; }
public string Sub_Section2 { get; set; }
public string Sub_Section3 { get; set; }
public int SectionType { get; set; }
public int Configuration { get; set; }
public List<SectionPart> SectionParts { get; set; }
}
class SectionPart
{
public double Length { get; set; }
public double Radius { get; set; }
}
so how can I diplay this sectionPart list ?
Add Newtonsoft.Json nuget :Install-Package Newtonsoft.Json to your project, and convert JSON to object using DeserializeObject
string data_from_json = #"[{'Name':'350SC250 - 14','Fy':33.0,'GFy':false,'T':0.0713,'GT':false,'D':2.5,'Stud_D':1.5,'C':0.0,'B':3.5,'GB':false,'Manufacturer':'BIDDLE','CFS_File':'350SC250 - 14.cfss','Sub_SectionCount':0,'Sub_Section1':'','Sub_Section2':'','Sub_Section3':'','SectionType':3,'Configuration':0,'SectionParts':[{'Length':0.375,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':3.0,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':2.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':3.0,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.375,'Radius':0.0}]}]";
dataGrid.Columns.Clear();
List<dataForm> all_date = JsonConvert.DeserializeObject<List<dataForm>>(data_from_json);
dataGrid.DataSource = all_date;
to display SectionParts only:
dataGrid.DataSource = all_date[0].SectionParts;
The problem you describe does not really have anything to do with JSON. The problem is with the Class dataForm. I do not like to say “problem” since the issue is fairly easy to understand, once you understand what your code is asking from the grid. The issue is that when the grid is given a DataSource like a List<T> or List<dataForm>, the grid will obligingly map each “primitive” property of the dataForm class (or any class T) to a column in the grid.
The grid is going to have to do something different when it comes across a property in the class that is a “Collection” or another “Class”. In this case, dataForm has a “collection” property …
public List<SectionPart> SectionParts { get; set; }
In this case the grid is not sophisticated enough to figure this out. It really is not going to know how to put “multiple” values into a single cell. Therefore, the grid will ignore collections as you obviously already know. This same Idea applies if the property in the class is another class… it will not display it.
Bear in mind, as other have commented, there are third-party controls that may have features that will show the collections or classes. Unfortunately, the out of the box DataGridView is fairly limited. In most cases, the easiest way to deal with this is in a “Master/Detail” type display, where the first grid displays the class and the second grid displays the collection of the “selected” item in the first grid.
With that said, there are ways to achieve your goal without a lot of work depending on “how” you want to “display” the data to the user. IMHO a master-detail is usually the easiest to implement and is user friendly. Another option, is to “flatten” each of the items in the collection creating a column(s) for each item in the collection. This is much more work and you will possibly end up with many columns and many empty cells… not user friendly. The last option which may work for your case is to create a public property in the dataForm class that “exposes” the SectionParts collection as a single string.
Example: in this case, the SectionPart class has two (2) properties.
public double Length { get; set; }
public double Radius { get; set; }
To help later, let’s override the ToString method to return the two values as a single string. Something like…
public override string ToString() {
return "L: " + Length + " R: " + Radius;
}
Moving to the dataForm class there is a “collection” of the SectionPart objects. To display ALL the section parts into a single cell we need to create a single string from ALL the section parts. Each part will be on a single line using the SectionParts ToString method we added above. To make this “single” string display in the grid, we need to add a new property to the dataForm class that returns this “list of parts” as a single string. This property may look like…
public string SectionPartsList {
get {
StringBuilder sb = new StringBuilder();
foreach (SectionPart sp in SectionParts) {
sb.AppendLine(sp.ToString());
}
return sb.ToString();
}
}.
You may need to adjust the grids rows height to accommodate, however, in my test, if you simply hover your cursor over the cell the list will display.
Lastly, for completeness, let us assume, that instead of a “List” of SectionParts the class had a single instance of this class.
public SectionPart SingleSectionPart { get; set; }
Again the grid is going to ignore this “class” property when creating the columns in the grid. However, if you wanted those two fields displayed in the grid, then it would be fairly simple to create two properties in the dataForm class that simply return those values. In this case, the two properties may look like…
public double SP_L {
get {
return SingleSectionPart.Length;
}
}
public double SP_R {
get {
return SingleSectionPart.Radius;
}
}
I hope this makes sense and helps.
The issue
Ok Hey guys, my issue is currently trying to think of the best way to edit data that exists in my application written in c# using WPF.
The application is small standalone app that uses XML to store rules on how to interpret hex messages and display it in human readable format.
Currently my app works fine, but i manually crafted the XML, i want to write something in the app that will allow layman users to make their own rule sets and save them to XML.
Now the saving to XML and the handling of the data once edited i am sure i can do, but i'm stumped over the best approach for XML.
Ok for brevity im just giving the general info and exluding some stuff - the classes i'm working with:
Rulesets
public class RuleSet
{
public string Name { get; set; }
public string LongName { get; set; }
public DateTime ReleaseDate { get; set; }
public string Base { get; set; }
public List<String> IncludedBulletins { get; set; }
public List<Byte> Bytes { get; set; }
public RuleSet(string name, string longName, string releaseDate, string #base)
{
ReleaseDate = parseDate(releaseDate);
Name = name;
LongName = longName;
Base = #base;
IncludedBulletins = new List<String>();
Bytes = new List<Byte>();
}
}
Bytes
public class Byte
{
public int ID { get; private set; }
public ReadMode Mode { get; private set; }
public List<Rule> Rules { get; set; }
public enum ReadMode
{
ASSORTED,
MULTI,
SINGLE
};
public Byte()
{
Rules = new List<Rule>();
}
}
Rules
public class Rule
{
public bool Active { get; private set; }
public int BytePos { get; private set; }
public int NibblePos { get; private set; }
public int Bit { get; private set; }
public int EndBit { get; private set; }
public int Value { get; private set; }
public int EndValue { get; private set; }
public string Translation { get; private set; }
public bool AllLowerBits { get; private set; }
public Rule()
{
Active = false;
Translation = "RFU";
}
}
Here is an example of the rules we interpret:
For Background info this is a Cardholder Verfication Method Rule passed in Banking applications between devices in Hexadecimal format and to interpret it is as described there.
I have a Catalog which is a list of rulesets stored in memory when the application loads initially it loads all the XML and parses it into the objects above which can then be interacted with in the app to provide meaningful information.
What i am struggling with is the best UI display i can make, i have considered a :
Treeview - with the rulesets and the children being the Bytes, display the properties for a ruleset in the upper part of a form, and when the user clicks on a byte it populated a section listing rules that can be added to with a new button that allows new rules to be made. This would require figuring out how to add a new byte to the treeview and allowing ordering of the treeview so the byte is correctly placed / maneuvered.
Listview With the rulesets only and data being displayed in a form as before but with tabcontrol for each byte, again this would require figuring out how to add a new byte to the treeview and allowing ordering of the treeview so the byte is correctly placed / maneuvered.
Something else you guys can suggest?
If anyone has any examples or links to tutorials for the needed things in the list or a better suggestion and examples that would be great I'm largely paralyzed trying to think of the best way to handle this data.
I'm running binary classifiers in ML.net. The output class looks like below, it has a "PredictedLabel" and through trial and error I've discovered the that "score" and "probability" are also valid. Where are the valid properties documented? And is there a property that I can use (with a corresponding name on the input data class) that will allow me to store a row id on the input data that will be output with the prediction?
Thanks
public class TargetData
{
[ColumnName("PredictedLabel")]
public bool Value { get; set; }
public float Score { get; set; }
public float Probability { get; set; }
}
ML.NET relies on schema comprehension to map the fields of an object to columns of a data view and back.
There is no limit on which columns your data view may have. For example, you could define your example class to be
public class Example
{
// Let's say your features are floats:
public float FeatureA;
public float FeatureB;
// ...
public bool Label;
// Here's an arbitrary RowId column.
public string RowId;
}
The RowId column will be created, and propagated all the way through the training, and it will be retained in the resulting model.
In order to read it back, just declare the field/property with the same name in your output class:
public class TargetData
{
[ColumnName("PredictedLabel")]
public bool Value { get; set; }
public float Score { get; set; }
public float Probability { get; set; }
public string RowId { get; set; }
}
The only limitation is on the allowed types: for example, you cannot declare GUID fields etc. The schema comprehension doc and the other linked docs define precisely which types are allowed.
I need to validate two fields only if a third field has a specific value.
In this code snipper i suppose to use a CheckIf properties that not exist.
It is possible to validate a field only if another property hase a specifica value ?
public string CustomerType { get; set; } // P=Private B=Business
[NotNullValidator(MessageTemplate = "You must specify the property 'Name'", CheckIf = "CustomerType=='P'")]
public string PrivateName { get; set; }
[NotNullValidator(MessageTemplate = "You must specify the property 'Name'", CheckIf = "CustomerType=='B'")]
public string BusinessName { get; set; }
Thank you!!!
From a validation perspective I agree with Siva that you can use SelfValidation for this. When looking at your code however, from an OO perspective, I can't help noticing that it might be good to take a good look at your design. It seems that either you are showing us two sub types of Customer, namely PrivateCustomer and BusinessCustomer:
class Customer
{
}
class PrivateCustomer : Customer
{
public string PrivateName { get; set; }
}
class BusinessCustomer : Customer
{
public string BusinessName { get; set; }
}
Or... those two properties are actually the same thing. Your validation messages even calls them 'Name' in both cases. In that case, you'll end up with this design:
class Customer : Customer
{
public string CustomerType { get; set; }
public string Name { get; set; }
}
I have an application that I'm trying to build with at least a nominally DDD-type domain model, and am struggling with a certain piece.
My entity has some business logic that uses some financial calculations and rate calculations that I currently have inside some domain services, as well as some constant values I'm putting in a value object.
I'm struggling with how to have the entity use the logic inside the domain services, or whether the logic inside those services even belongs there. This is what I have so far:
public class Ticket
{
public Ticket(int id, ConstantRates constantRates, FinancialCalculationService f, RateCalculationService r)
{
Id = id;
ConstantRates = constantRates;
FinancialCalculator = f;
RateCalculator = r;
}
private FinancialCalculationService FinancialCalculator { get; set; }
private RateCalculationService RateCalculator { get; set; }
private ConstantRates ConstantRates { get; set; }
public int Id { get; private set; }
public double ProjectedCosts { get; set; }
public double ProjectedBenefits { get; set; }
public double CalculateFinancialGain()
{
var discountRate = RateCalculator.CalculateDiscountRate(ConstantRates.Rate1, ConstantRates.Rate2,
ConstantRates.Rate3);
return FinancialCalculator.CalculateNetPresentValue(discountRate,
new[] {ProjectedCosts*-1, ProjectedBenefits});
}
}
public class ConstantRates
{
public double Rate1 { get; set; }
public double Rate2 { get; set; }
public double Rate3 { get; set; }
}
public class RateCalculationService
{
public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
{
//do some jibba jabba
return 8.0;
}
}
public class FinancialCalculationService
{
public double CalculateNetPresentValue(double rate, params double[] values)
{
return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
}
}
I feel like some of that calculation logic does belong in those domain services, but don't really like that I'll have to manually inject those dependencies from my Repository. Is there an alternate way that this should be modeled? Am I wrong in not liking that?
Having read the Blue Book but not really built anything in this style before, I'm looking for guidance.
EDIT
Thanks all for the feedback! Based on what I'm hearing, it sounds like my model should look more like the following. This look better?
public class Ticket
{
public Ticket(int id)
{
Id = id;
}
private ConstantRates ConstantRates { get; set; }
public int Id { get; private set; }
public double ProjectedCosts { get; set; }
public double ProjectedBenefits { get; set; }
public double FinancialGain { get; set; }
}
public class ConstantRates
{
public double Rate1 { get; set; }
public double Rate2 { get; set; }
public double Rate3 { get; set; }
}
public class FinancialGainCalculationService
{
public FinancialGainCalculationService(RateCalculationService rateCalculator,
FinancialCalculationService financialCalculator,
ConstantRateFactory rateFactory)
{
RateCalculator = rateCalculator;
FinancialCalculator = financialCalculator;
RateFactory = rateFactory;
}
private RateCalculationService RateCalculator { get; set; }
private FinancialCalculationService FinancialCalculator { get; set; }
private ConstantRateFactory RateFactory { get; set; }
public void CalculateFinancialGainFor(Ticket ticket)
{
var constantRates = RateFactory.Create();
var discountRate = RateCalculator.CalculateDiscountRate(constantRates.Rate1, constantRates.Rate2,
constantRates.Rate3);
ticket.FinancialGain = FinancialCalculator.CalculateNetPresentValue(discountRate,
new[] {ticket.ProjectedCosts*-1, ticket.ProjectedBenefits});
}
}
public class ConstantRateFactory
{
public ConstantRates Create()
{
return new ConstantRates();
}
}
public class RateCalculationService
{
public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
{
//do some jibba jabba
return 8.0;
}
}
public class FinancialCalculationService
{
public double CalculateNetPresentValue(double rate, params double[] values)
{
return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
}
}
The domain model ends up being fairly anemic at this point, but as I add features maybe it'll have more to it.
EDIT 2
Okay, I got some more feedback that perhaps my 'calculation' services are more like strategy objects that it's okay for my Entity to depend on. Here's another take at it with more of the logic back in the Entity, and making use of those strategy objects. Thoughts on this? Any issues with instantiating those helpers directly in the Entity? I don't think I'll want to mock those out in my tests, but OTOH I can't test the CalculateFinancialGain method without testing those strategy objects, either.
public class Ticket
{
public Ticket(int id, ConstantRates constantRates)
{
Id = id;
ConstantRates = constantRates;
}
private ConstantRates ConstantRates { get; set; }
public int Id { get; private set; }
public double ProjectedCosts { get; set; }
public double ProjectedBenefits { get; set; }
public double CalculateFinancialGain()
{
var rateCalculator = new RateCalculator();
var financeCalculator = new FinanceCalculator();
var discountRate = rateCalculator.CalculateDiscountRate(ConstantRates.Rate1, ConstantRates.Rate2,
ConstantRates.Rate3);
return financeCalculator.CalculateNetPresentValue(discountRate,
ProjectedCosts*-1,
ProjectedBenefits);
}
}
public class ConstantRates
{
public double Rate1 { get; set; }
public double Rate2 { get; set; }
public double Rate3 { get; set; }
}
public class RateCalculator
{
public double CalculateDiscountRate(double rate1, double rate2, double rate3 )
{
//do some jibba jabba
return 8.0;
}
}
public class FinanceCalculator
{
public double CalculateNetPresentValue(double rate, params double[] values)
{
return Microsoft.VisualBasic.Financial.NPV(rate, ref values);
}
}
Have your service accept the Ticket entity as a parameter. Services should be stateless and the same service should be able to provide its services to any number of entities.
In your situation I would pull the FinancialCalculatorService and RateCalculatorService out of your entity and make the methods on each service accept the Ticket entity as a parameter.
Take a second and read pg. 105 of Domain-Driven Design by Eric Evans
Given what we've seen of the classes, I don't think they're really services in the blue book sense, and I would keep the calculators in Ticket.
Neither FinancialCalculatorService or RateCalculationService has dependencies on domain entities - they both operate on primitive values. Applications shouldn't have to worry about how to calculate the financial gain that would result from a ticket, so it's valuable to encapsulate that information inside the ticket itself.
If they really don't have dependencies on domain entities, consider thinking of them as 'standalone classes' rather than 'services' (once again, in blue book terminology). It's certainly appropriate for Ticket depend on strategy objects (FinancialCalculator and RateCalculator) that do not themselves have exotic dependencies and do not themselves modify the state of domain entities.
Update for Edit 2. I think one of the advantages of making the calculators separate classes is that you can test them independently of Ticket. Strictly speaking, tickets aren't responsible for performing those calculations, they're responsible for making the right calls to those collaborating classes. So I'd be inclined to make them inject-able / mock-able as they were in your initial example.
i would say services use entities, not the other way around.
another thing, not sure on your domain, but are you certain ticket is an entity and not a value object?
You've actually struck on a question that there has been quite a bit of discussion on. There are believers on both sides of the tracks so you need to decide for yourself what makes the most sense.
Personally I don't have my entities use services as it creates a whole lot of work around the "How do I cleanly get services into my entities?" question.
It looks to me like CalculateFinancialGains() is more of a service level call. This does lead to Ticket being very anemic but I assume it has other behavior? And if it doesn't that's probably a smell...
This question is actually an example of a discussion that is in the book "Clean Code" (pp 96-97). The underlying question is whether or not to use a procedural approach or a object oriented approach. Hope I'm not in violation repeating a couple parts here, but here is what Bob Martin states for guidance:
Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.
The compliment is also true:
Procedural code makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.
My understanding that a DDD "Value type" would be what Bob Martin calls a data structure.
Hope this helps and doesn't just add to the noise :)