I have an application following the MVVM pattern, that has to serialize XML files. As some of the XML attributes are nested, I've created nested classes inside my Model, like this:
public class OPER_FILE
{
public UNB unb { get; set; }
public OPER oper { get; set; } //nested class, level 1
public OPER_FILE()
{
unb = new UNB();
oper = new OPER();
}
}
public class OPER
{
public UNH unh { get; set; } //these are all nested classes, level 2
public UVT uvt { get; set; }
public VIN vin { get; set; }
public OPER()
{
unh = new UNH();
uvt = new UVT();
}
}
#region "nested classes"
public class UNB
{
public string unb { get; set; }
public string unb_2 { get; set; }
}
public class UNH
{
public string unh { get; set; }
public string unh_2 { get; set; }
}
public class UVT
{
public string uvt { get; set; }
public string uvt_1 { get; set; }
public string uvt_2 { get; set; }
}
public class VIN
{
public string vin { get; set; }
public string vin_1 { get; set; }
public string vin_2 { get; set; }
public string vin_3 { get; set; }
public string vin_4 { get; set; }
}
#endregion
The attributes of the nested classes are all strings, because this simplifies the XML serialization for now (I'm still in the conception phase).
In my corresponding ViewModel, I've simply created a property for the nested class inside the model, so I can access all of the nested properties with just referring to this nested class from the ViewModel.
public class OPERViewModel : IViewModelBase
{
private OPER_FILE Model;
public UNB unb
{
get
{ return Model.unb;}
set
{ Model.unb = value; }
}
public OPER oper
{
get
{ return Model.oper; } //this is the tricky part, by now I'm just referring to the nested class as a property of the model
set
{ Model.oper = value; }
}
public OPERViewModel()
{ Model = new OPER_FILE(); }
}
The question is, however, that I want to display some of the properties not as strings but as boolean values using checkboxes on the UI.
Saying I want to display Model.oper.vin.vin_1 as boolean (where the ViewModel should manage the conversion from string to bool in the getter of its own property reflection of Model.oper.vin.vin_1), how would I do that?
Would I really have to implement every nested property from a nested class as an own property of the ViewModel (like stated below) to gain control over the way it will be returned to the UI?
//ViewModel-implementation with type-conversion of a property from a nested class of the model
//this would get bind to the UI instead of Model.oper.vin.vin_1
public bool vin_1
{
get
{
if (Model.oper.vin.vin_1 == "1")
{ return true; }
else
{ return false; }
}
set
{
if (value)
{ Model.oper.vin.vin_1 = "1"; }
else
{ Model.oper.vin.vin_1 = "0"; }
}
}
I hope there is a better solution out there...
Edit:
What I forgot to mention before, there're not only strings that have to be displayed as booleans, also DateTime-values that should be displayed as a DatePicker-control, integer-values that I would like to have as NumberPickers and so on.
The xml-file, on the other hand, will be consumed by an interface with some pretty fixed regulations that i need to match, such a dynamically leading zeros on both integer- and float-values, special date formats and commas instead of dots as decimal separators. So sticking with the string-values inside the object to serialize is a good way of maintaining control over how the values would get actually parsed inside the xml-file.
I'll try and experiment with some different converters, as #BrandlyDOTNet reommended, but are still curious about how this could be solved in another way.
There's a different solution out there, namely that you can use a converter to define the translation between your strings and a bool.
Something like:
public class StringToBoolConverter : IValueConverter
{
public object Convert(...)
{
return value.ToString() != "0";
}
public object ConvertBack(...)
{
bool boolVal = (bool)value;
return boolVal ? "1" : "0";
}
}
Usage:
<CheckBox IsChecked={Binding SomeProp, Converter={StaticResource StringToBoolConverter}"/>
But to answer your deeper question, no, the framework will not just convert the string "1" into a bool. Moreover, you can strongly type your object that is being serialized, so none of this is actually necessary.
Related
The sub class isn't derived from the main class, I'm just trying to differentiate them.
Even as I type this I can see it being impossible but I have some classes:
public class TransferServiceInformation {
public int ProviderId { get; set; }
public string PrePurchaseOverride { get; set; }
public bool PrePurchaseOverrideEnabled { get; set; }
}
and
public class TransferServiceProviderInformation {
public int ProviderId { get; set; }
public string PrePurchaseInfo { get; set; }
And I want it so that if I ever try to access myTransferServiceInformation.PrePurchaseOverride and PrePurchaseOverrideEnabled == false it should return PrePurchaseInfo from the TransferServiceProviderInformation with the same ID.
Is something like that even possible?
I'm just having a thought that a getter that requires a TransferServiceProviderInformation passed as an argument might work, and throw an exception if the IDs don't match. Is that the only solution? The thing is, I'd rather not have to dig through all the (thousands of lines of) code to change all the places were I (or someone else) has called this property.
This is just an idea:
Make a static list with instances inside your class and auto-fill it with using the constructor. Then you can check this list from outside for instances with the same id.
public class TransferServiceInformation
{
public int ProviderId { get; set; }
private string prePurchaseOverride;
public string PrePurchaseOverride
{
get
{
if(!PrePurchaseOverrideEnabled)
{
// Get instances from the other class where providerID matches
var instance = TransferServiceProviderInformation.Instances.Where(i => i.ProviderId == this.ProviderId).FirstOrDefault();
if(instance != null)
return (instance).PrePurchaseInfo;
}
return null; // If no match found
}
set
{
prePurchaseOverride = value;
}
}
private bool prePurchaseOverrideEnabled;
public bool PrePurchaseOverrideEnabled { get; set; }
}
public class TransferServiceProviderInformation
{
// Store your instances static
public static List<TransferServiceProviderInformation> Instances { get; set; }
public TransferServiceProviderInformation()
{
// Add every new instance to the list
Instances.Add(this);
}
public int ProviderId { get; set; }
public string PrePurchaseInfo { get; set; }
}
To-do's:
If an instance gets disposed, delete it from the list of instances.
I have an application serving multiple websites and would like to setup colour scheming like this:
Each element (link, text, heading, etc) has a default for the application
Each element can be overridden for individual websites
If an element is set to application default, the custom colour should be remembered for future reference
Website Configuration.cs
public class WebsiteConfiguration
{
public ApplicationConfiguration ApplicationConfiguration { get; set; }
public string CustomLinkColour { get; set; }
public bool IsCustomLinkColourActive { get; set; }
public string LinkColour
{
get
{
return (IsCustomLinkColourActive ? CustomLinkColour : ApplicationConfiguration.DefaultLinkColour);
}
}
public string CustomTextColour { get; set; }
public bool IsCustomTextColourActive { get; set; }
public string TextColour
{
get
{
return (IsCustomTextColourActive ? CustomTextColour : ApplicationConfiguration.DefaultTextColour);
}
}
// ...and so on for each colour scheme element...
}
ApplicationConfiguration.cs
public class ApplicationConfiguration
{
public List<WebsiteConfiguration> WebsiteConfigurations { get; set; }
public string DefaultLinkColour { get; set; }
public string DefaultTextColour { get; set; }
//... and so on for each colour scheme element...
}
Problems
It's a lot of work!
There are just 2 colour scheme elements in the examples above, but there may be 50+ of them.
Also, it is creating a lot of work in the view files, with if else blocks etc.
Attempted Solution
A ColourSchemeItem class manages the logic.
public class ColourSchemeItem
{
public string DefaultColour { get; set; }
public string CustomColour { get; set; }
public bool IsCustomColourActive { get; set; }
public string ActiveColour
{
get
{
return (IsCustomColourActive ? CustomColour : DefaultColour);
}
}
}
And then WebsiteConfiguration becomes much simpler...
public class WebsiteConfiguration
{
public ApplicationConfiguration ApplicationConfiguration { get; set; }
public ColourSchemeItem Link { get; set; }
public ColourSchemeItem Text { get; set; }
// ...and so on for each colour scheme element...
}
However...
But somehow I need to get the default colour from the ApplicationConfiguration into the ColourSchemeItem. And I can't figure out how.
If the ColourSchemeItem contains a reference to it's parent - WebsiteConfiguration - I get a No Key Defined for Entity error.
If ColourSchemeItem does NOT contain a reference to it's parent, I can't access the default colour from WebsiteConfiguration.ApplicationConfiguration.
The only other option I can think of it to access the DB directly from within the ColourSchemeItemclass. If there are going to be 50+ of these, I don't want to do that.
Create a custom constructor, and set the default to AplicationConfiguration
In the below example, I'm just trying to get Test_Person_Name.FirstName to map to something (anything) in TestPersonFlattened. At this point, considering the amount of time I've sunk into this, I'm not too hung up on what the destination property name is..I just want it to work.
public class Test_Person
{
public Test_Person_Name Test_Person_PublicName { get; set; }
}
public class Test_Person_Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class TestPersonFlattened
{
public string Test_Person_PublicNameFirstName { get; set; } // What do I call this property?
}
AutoMapper.Mapper.CreateMap<Test_Person, TestPersonFlattened>();
AutoMapper.Mapper.AssertConfigurationIsValid();
It seems like Test_Person_PublicNameFirstName should work, but I get an exception on AssertConfigurationIsValid(). I've also tried TestPersonPublicNameFirstName, Test_Person_PublicName_FirstName as destination property names.
It'd be unfavorable to rename the source property name, just because the source library is used in many other projects. Also, a ForMember() call isn't ideal, but I'll do it if there's no other option.
One way to do it would be to simply leave out "Test_Person_" from the PublicNameFirstName property of your TestPersonFlattened class, and use RecognizePrefixes() to make it so that AutoMapper ignores "Test_Person_" when attempting to map property names.
The following code succeeds:
public partial class App : Application
{
public App()
{
Mapper.Initialize(cfg =>
{
cfg.RecognizePrefixes("Test_Person_");
cfg.CreateMap<Test_Person, TestPersonFlattened>();
});
Mapper.CreateMap<Test_Person, TestPersonFlattened>();
Mapper.AssertConfigurationIsValid();
}
}
public class Test_Person
{
public Test_Person_Name Test_Person_PublicName { get; set; }
}
public class Test_Person_Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class TestPersonFlattened
{
public string PublicNameFirstName { get; set; } // This is what I call this property!
}
I started using EF with Code First recently and have come upon this issue which has left me rather perplexed. I will appreciate any feedback on this topic which will help me in resolving the said issue.
Please consider the following sample....
public class SomeType
{
public SomeType()
{
Properties = new List<BaseProperty>();
}
public int PrimaryKey { get; set; }
public string Name { get; set; }
public List<BaseProperty> Properties { get; set; }
}
public abstract class BaseProperty
{
public int PrimaryKey { get; set; }
public string PropertyName { get; set; }
// FK set through Type Configuration File.
public SomeType ParentInstance { get; set; }
}
public class PropertyA : BaseProperty
{
// some unique properties.
}
public class PropertyB : BaseProperty
{
// some unique properties.
}
public class PropertyC : BaseProperty
{
// some unique properties.
}
public class PropertyD : BaseProperty
{
// some unique properties.
}
All of this works great with the appropriate type configuration classes which map to 2 tables (1 for 'SomeType' and the second for 'BaseProperty' along with the remaining derived entities through the use of a discriminator column).
Now, due to circumstances beyond my control, I am being forced to modify 'SomeType' to something like this....
public class SomeType
{
public SomeType()
{
PropertiesAB = new List<BaseProperty>();
PropertiesC = new List<PropertyC>();
PropertiesD = new List<PropertyD>();
}
public int PrimaryKey { get; set; }
public string Name { get; set; }
public List<BaseProperty> PropertiesAB { get; set; } // collection of PropertyA and PropertyB
public List<PropertyC> PropertiesC { get; set; } // collection of PropertyC
public List<PropertyD> PropertiesD { get; set; } // collection of PropertyD
}
This would be very fairly easy to do in NHibernate using bags but is there an equivalent implimentation for this in EF using Code First ? Any thoughts ?
I do not want to write my own implimentation of a Collection which will forward and manipulate all operations to be performed on these new lists to a master list which will be actually mapped to the database.
Please ignore any missing "virtual" modifiers or anything else in the above code since it is only meant to be a sample and is NOT actually what I am using.
Thank you for your replies.
Worse comes to Worse, you can do something like this:
public class SomeType
{
public SomeType()
{
Properties = new List<BaseProperty>();
}
public int PrimaryKey { get; set; }
public string Name { get; set; }
public List<BaseProperty> Properties { get; set; }
public List<BaseProperty> PropertiesAB
{
get
{
return Properties.Where(p=>p is PropertyA || p is PropertyB);
}
set
{
//Remove all the properties already in the Properties collection of
//the type A and B and then
Properties.AddRange(value)
}
}
//Same with rest of the properties
}
You can also make the Properties property internal if the class is being used outside the domain layer
I have a number of classes that are all related conceptually, but some more-so at the details level than others. For example, these three classes have nearly identical properties (although member functions will vary):
public class RelatedA : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
}
public class RelatedB : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
}
public class RelatedC : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
public int Special { get; set; }
}
There are a couple of other classes that are conceptually related to the above 3, but can be a bit different implementation-wise:
public class RelatedD : IRelatedType
{
public string Name { get; set; }
public string Statement { get; set; }
}
public class RelatedE : IRelatedType
{
public string Name { get; set; }
public string Statement { get; set; }
public bool IsNew { get; set; }
}
Instances of these can be created by a factory based on some sort of "type" enumerated value. The problem is that later on when these objects are being used (in a business layer, for example), there could be a lot of code like this:
IRelatedType theObject = TheFactory.CreateObject(SomeEnum.SomeValue);
if (theObject is RelatedC)
{
RelatedC cObject = theObject as RelatedC;
specialVal = cObject.Special;
}
else if (theObject is RelatedD)
{
RelatedD dObject = theObject as RelatedD;
statementVal = dObject.Statement;
}
else if (theObject is RelatedE)
{
RelatedE eObject = theObject as RelatedE;
statementVal = eObject.Statement;
isNewVal = eObject.IsNew;
}
This could be repeated in many places. Is there a better approach to the design that I should be using (there's got to be)?
You could try and factor the differences into seperate classes that are then provided so for example:
IRelatedType theObject = TheFactory.CreateObject(SomeEnum.SomeValue);
RelatedTypeHelper theHelper=TheFactory.CreateHelper(theObject);
theHelper.DoSpecialThing(theObject);
Now you won't have to have all the if else blocks, and if you add a new type which requires new handling, you just whip up a new helper implement the required pieces and you should be good to go. The helper should help document this process.
I would also question why a single method would have such a different implementation for specialVal and StatementVal could be your sample, but It makes me curious what your really doing here. can you simplify things back taking a step back and questioning the point of these being included in this specific hierarchy.