Using System.ComponentModel.DisplayName with dynamic values? - c#

Im trying to implement multi-language support in my system,
the other systems at work uses xmlfiles for this generated from a database that they have used for some time now so they want me to use this aswell.
I have managed to translate everything except the displaynames in my formmodels, these values can apperantly only be constant values so i can't use a method that gets the correct translation.
This is how the code is now:
[System.ComponentModel.DisplayName("Kontraktnamn")]
public string Name { get; set; }
And i want to do something like this:
[System.ComponentModel.DisplayName(GetTextByKey("Contract_Name"))]
public string Name { get; set; }
Is it possible to work around this? Or maybe there is a better way to do it and still use the xmlfiles?

You'll need to create your own custom attribute that can read the xml values:
public class CustomDisplayName : DisplayNameAttribute
{
public CustomDisplayName()
{
this.DisplayName = MyXmlReader.Read(DisplayName);
}
}

Related

How to cache data in C# in the simplest and most elegant way?

I am writing an audiobook app in C# .NET Framework. I need to store on user disc information about audiobooks' locations and last listened audiobooks. I'm looking for the simplest and the most elegant way to do it. As easy as it can be.
What is the best (safe and proper) way to do it? How you would do it?
A very simple way is to create a custom class that holds properties for each setting you want to persist between sessions. Then create an instance of this class and set the properties with the values you want to persist.
Finally serialize the instance with a Json library transforming it in a string and save it to a location where you have read/write permissions.
To retrieve the information just do the reverse, read from the file, deserialize the string into an instance of your setting class and then use it.
So supposing a class like this:
public class ApplicationSettings
{
public string LastBookName { get; set; }
public List<string> PreviousTitles { get; set; }
}
You can have two helper methods like these one (making use of NewtonSoft.Json library NuGet here)
public void SaveSettings(ApplicationSettings aps)
{
string json = JsonConvert.SerializeObject(aps);
File.WriteAllText(#"E:\temp\savedsettings.json", json);
}
public ApplicationSettings LoadSettings()
{
string json = File.ReadAllText(#"E:\temp\savedsettings.json");
return JsonConvert.DeserializeObject<ApplicationSettings>(json);
}
Now you just need to call these two methods in the appropriate points of your code.

Unique attribute for each property

I have written an attribute class which I later used for sorting properties.
[AttributeUsage(AttributeTargets.Property)]
class OrderAttribute : Attribute
{
internal OrderAttribute(int order)
{
Order = order;
}
public int Order { get; private set; }
}
I want this to be unique for class properties, e.g.
Valid scenario
[Order(1)]
public string Tier3 { get; set; }
[Order(2)]
public string Tier4 { get; set; }
Invalid Scenario since value "1" is repeated.
[Order(1)]
public string Tier3 { get; set; }
[Order(1)]
public string Tier4 { get; set; }
PS: Attribute values can be repeated for different class properties but not in same. How can I achieve this?
Although attribute values can be repeated, there's no easy way supported to make sure they are unique (they are run time only), you would need to check when actually sorting as Johnathan has already mentioned. There are ways around this, but is it worth it in the long run? A few options I can think of are:
Hook into the actual build process, create a build task that uses reflection to check and fail if needed.
Run a post-build (post build event) step that loads your dll and reflects on those attribute types.
Create a possible rule that will check for uniqueness.
There may be other ways, but these are the one's I could think of at the moment.

How to set up a C# model to convert properties to Knockout computed observables

We're using durandal to convert C# models to Knockout viewmodels for rendering. I'm wondering if there's a way I can set up a C# model with properties that have a set method or something so that the bindings and dependencies are already present when I get the Knockout viewmodel.
I'd like a scenario like this to happen.
public class MyObject{
public string FirstName{get; set;}
public string LastName {get; set}
private string fullName{get; set;}
public FullName{
get{return fullName;}
set{fullName = FirstName +" "+LastName}
}
I've used the prime example Knockout uses when explaining computed observables. I understand how to achieve this in purely JS viewmodel. However, I'd like to set up my C# model similar to what I have above (I don't think this actually works) in order to get back a computed that already has it's dependencies.
I'm not entirely sure it's possible, but it sure would be nice.
Max Brodin mentions KnockoutMVC which is a huge antipattern and you lose almost all benefits with Knockout since it creates server callbacks for almost everything you do.
A better option is to use for example DuoCode or Open source alternative WootzJs
These tools will compile C# code to Javascript, I have only tested DuoCode but it was farily easy to create a Knockout binding for it. After that its easy to create ViewModels like
using Knockout;
namespace ViewModels
{
public class FooViewModel
{
private readonly Observable<string> bar;
private readonly Observable<string> computed;
public FooViewModel()
{
bar = Global.Observable("HelloWorld"); //Translates to ko.observable("HelloWorld") on client
computed = Global.Computed(() => bar.Get() + "COMPUTED");
}
public Observable<string> Bar { get { return bar; } }
public Observable<string> Computed { get { return computed; } }
}
}
I have also created bindings for ko.mapping like
Mapping.Map(new { bar = "DataFromserver" }, null, this); which translates to
ko.mapping.fromJS({ bar = "DataFromserver" }, null, this); on client
The idea is good, but it's not going to work in the real world projects. Your C# code need to be translated to javascript and it could work for simple cases like yours. But if you change your computed property to more something complicated you will have problems.
There is a knockoutmvc project that provides such functionality. They have hello world sample which looks like something you can use as a start. You just need to mark your property with attributes
public class HelloWorldModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
[Computed]
[ScriptIgnore]
[JsonIgnore]
public string FullName
{
get { return FirstName + " " + LastName; }
}
}
And in razor view you should call:
#{
var ko = Html.CreateKnockoutContext();
}
#ko.Apply(Model)
You seem to want auto-translation of computed properties. That's a big ask for a small convenience. I think I could do it for trivial expressions, but how would you map .NET library methods like string.Format to javascript? You would need a client side library replicating the semantics. Big job, not worth the effort.

Inheriting from a class and adding an additional property

I have a class in one application - that I cannot change (legacy) - that is inside of a assembly (DLL file):
public class ShippingMethod
{
public string ShipMethodCode { get; set; }
public string ShipMethodName { get; set; }
public decimal ShippingCost { get; set; }
public List<ShippingMethod> GetAllShippingMethods()
{
......
}
}
I have a second application that is referencing that assembly (DLL file) and needs to populate a drop-down with all the Shipping Methods. Ex: "UPS - $3.25"
The issue is that it needs to be using the correct format for different currencies. Ex: $3.25 or 3.25€ depending on a parameter called CountryID.
I have written a function String DisplayMoney(Decimal Amount, Integer CountryID) that will return the correct format of the amount.
Now I need to apply this function to every shipping method and save it into a new list.
What is the best way to do this?
I can create another class called LocalizedShippingMethods as follows:
public class LocalizedShippingMethod
{
public ShippingMethod ShipMethod { get; set; }
public string LocalizedShippingCost { get; set; }
}
Is this the best way to accomplish this? Is there a better way to do this using inheritance? And if I use inheritance, how do I get the values from the first LIST into the NEW LIST?
That is indeed a good method of doing it. You can use a pretty quick Linq query to pull the old List into the new one:
List<LocalizedShippingMethod> Translate(List<ShippingMethod> oldList)
{
return oldList.Select(a => new LocalizedShippingMethod
{
// Initialize properties according to however you translate them
}).ToList();
}
Additionally, to make this more streamlined and obvious, you could do any of the following to aid in the translation:
Create a constructor for LocalizedShippingMethod that takes in a ShippingMethod and properly sets the properties
Create a static method on LocalizedShippingMethod that takes in a ShippingMethod and returns an initialized LocalizedShippingMethod
Create an operator on LocalizedShippingMethod that converts from a ShippingMethod
Create an extension method on ShippingMethod, call it ToLocalized() that returns a LocalizedShippingMethod
What if you create an extension method for the ShippingMethod class?
The best way to do this is whatever way works best for you. If you're the person who's going to have to maintain this code, what will make your life the easiest down the road?
Once you've answered that question, that is the best solution.

How to make a Attribute aware of the Name of the Proprty it is on?

I want to implement a simple attribute that is used to map Database Columns to Properties.
So what i have so far is something that attached like so:
[DataField("ID")]
public int ID { get; set; }
[DataField("Name")]
public String Name { get; set; }
[DataField("BirD8")]
public DateTime BirthDay { get; set; }
Is there a way that I can make the attribute "aware" of the field it is on, so that for the properties where the name is the same as the ColumnName I can just apply the attribute without the name parameter, or would I have to deal with that at the point where I reflect the properties. I want to end up doing just this:
[DataField]
public int ID { get; set; }
[DataField]
public String Name { get; set; }
[DataField("BirD8")]
public DateTime BirthDay { get; set; }
The attribute itself won't be aware of what it's applied to, but the code processing the attributes is likely to be running through PropertyInfo values etc and finding the attributes associated with them. That code can then use both the property and the attribute appropriately.
To make things simpler, you might want to write a method on the attribute to allow it to merge its information with the information from the property, so you'd call:
DataFieldAttribute dfa = propertyInfo.GetCustomAttributes(...); // As normal
dfa = dfa.MergeWith(propertyInfo);
Note that for the sake of sanity this should create a new instance of the attribute, rather than changing the existing one. Alternatively, you might want a whole separate class to represent "the information about a data field":
DataFieldAttribute dfa = propertyInfo.GetCustomAttributes(...); // As normal
DataFieldInfo info = dfa.MergeWith(propertyInfo);
That way you could also construct DataFieldInfo objects without any reference to attributes, which might be a nice conceptual separation - allowing you to easily load the config from an XML file or something similar if you wanted to.
If you don't mind using postsharp you can look Here, at a previous question I have asked which was close. I ended up using the compile time validate to do what I wanted, although there are other options, like CompileTimeInitalize.
public override void CompileTimeInitialize(object element)
{
PropertyInfo info = element as PropertyInfo;
//....
}

Categories