I would like to know if there is a maneer (may be with data annotation) to set the value of
property.DisplayPropertyName
.
Do you have any idea please?!!
Actually I think you mean to ask how you can choose a different property as the display property (i.e., the property that is used to briefly denote objects of your class in the UI).
The Entity Framework Service that generates the metadata for scaffolding choose the first property of string type (as far as I know), but you can change that by applying the DisplayColumn attribute to your class:
[DisplayColumn("Alias")]
public class Person {
public string Name { get; set; }
public string Alias { get; set; }
}
Note, however, that this only works for properties that are actually mapped to a column in the database. (I was trying to use a computed property, not mapped, but that led to an error message while scaffolding.)
That is quite easy to do:
[DisplayName("RenamedProperty")]
you can even add a description
[Description("Demonstrates DisplayNameAttribute.")]
or perhaps you would like it to reference your resources so it adapts itself to the selected language:
[Display(Name = "Description", ResourceType = typeof(Resources))]
Related
Interfaces are no types, so when implementing them, their property attributes are not inherited. (which would be true of a base-class)
So, I'm currently wrapping my head around how to make this happen. Following example should pretty much explain what I mean, but unfortunately is not working as expected.
Reason is obvisously to centralize Instructions / Attributes without having to copy / paste them over and over.
public interface IPermissionBasedControl
{
[Browsable(true), Category("PermissionSystem"), Description("AccessKey required in order to use this control.")]
String PermissionKey { get; set; }
}
public class ExtendedTextBox : TextBox, IReadOnlyControl, IDataBindable, IPermissionBasedControl
{
...
[AttributeProvider(typeof(IPermissionBasedControl))]
public string PermissionKey { get; set; }
...
}
Expectation: Visual Studio Designer will pick the Category, Browsable and Description Attribute from IPermissionBasedControl and display the property PermissionKey accordingly in the Designers Property-Window, when working with a ExtendedTextBox.
Actual result: Nothing happens, Default Category Misc is applied, no Description, Browsable default yes is applied.
Is it not working, because Visual Studio Designer does not respect the AttributProvider-Attribute?
Is it not working, because AttributeProvider cannot target an Interface?
I've also tried method access to no success:
public class ExtendedTextBox : TextBox, IReadOnlyControl, IDataBindable, IPermissionBasedControl
{
...
[AttributeProvider(nameof(IPermissionBasedControl), nameof(IPermissionBasedControl.PermissionKey))]
public string PermissionKey { get; set; }
...
}
Okay, It seems like I had a wrong interpretation about what AttributeProvider is doing:
AttributeProviders description is Enables Attribute Redirection - but this doesn't mean, that it will (in my example) attach the Attributes of IPermissionBasedControl.PermissionKey to ExtendedTextBox.PermissionKey, the AttributeProvider is having effect on the Attributes of the type of the property.
i.e.: If I would specify
[AttributeProvider(typeof(Color))]
public object PermissionKey { get; set; }
the VisualStudio Designer would now Apply the Attributes of Color to the Value-Field for picking the object. (And therefore show a color-picker)
So, technically spoken, the AttributeProvider redirects Attributes for the type of the property, not for the property itself.
In order to build a custom transpiler, I'm trying to get the default value of all the properties inside a class as an expression, and not as a value itself.
Let me bring you some examples to clarify what I'm trying to do and what I've done/tried/investigated so far.
Source code could be the following one:
const string DATETIME_NOW = "____DATETIME_NOW____";
public class Person {
[DefaultValue("Foo")]
public string Name { get; set; } = "Foo";
[DefaultValue(DateTime.Now)] // This is not doable: "An attribute argument must be a constant expression"
public DateTime DateOfBirth { get; set; } = DateTime.Now;
[DefaultValue(DATETIME_NOW)]
public string DateOfBirthStringed { get; set; } = DATETIME_NOW; // which acts like DateTime.Now.ToString()
}
The ultimate goal of the transpiler, is to obtain a Javascript class that looks like this:
class Person {
name: string = "Foo";
dateOfBirth: Date = new Date(Date.now());
dateOfBirthStringed : Date = Date.now();
}
My current, and working, implementation is the use of DefaultValue attribute with some constants strings used when the default value is an expression (e.g. DateOfBirthStringed).
What I'm doing is using reflection on Person, getting all the PropertyInfo, looking for their DefaultValue attribute, and then checking if the given default value are some fixed constants like DATETIME_NOW.
This works, but I've a couple of problems:
The type in attribute DefaultValue could be different from the type of the property.. No type check :(
If I only have the DefaultValue, when I write new Person(), the default values are not actually set from the attribute.
Therefore, I need to write the default value after { get; set; }, but:
Or I wrote both attribute and default value, but then I should manually mantain synchronized them.
I write only the default value, but then I've no way to get it with reflection.
About point 3.2, why I can't get the default value via reflection?
Suppose the Person class defined above; if I use reflection, I need to instantiate it, but once instantiated, Person.DateOfBirth has an actual DateTime value, and I cannot know it was coming from DateTime.Now.
Also, if Person would be abstract.. Well, no way to instantiate it.
So, basically, the only way I could perfectly transpile the code is to read the code as a tree, something like parseTreeCode(typeof(Person)). At that point, I should navigate the tree and be able to do everything I want.
I did find Roslyn, which allows me to parse C# code, but.. It parses "stringed" code, and not code that belongs to the same project. I thought "well, get the file where Person is defined, and parse the whole file", but unfortunately, once the program is running, I cannot get the file where Person is defined.. I mean, I can do typeof(Person).Assembly, and getting the Assembly.. But it would be an assembly, so it would not be good.
At this point, I'm thinking that there is no real solution for this, but maybe I'm missing some C# packages/features that could help me
I want to display multiple instances of one class in my PropertyGrid. The class looks like this:
public class Parameter
{
[Description("the name")]
public string Name { get; set; }
[Description("the value"), ReadOnly(true)]
public string Value { get; set; }
[Description("the description")]
public string Description { get; set; }
}
I have many instances of that class in a TreeView. When I select one of them in my TreeView, the properties show up in the PropertyGrid as expected. So far so good, but I want to customise this behaviour in the following way:
For each single instance I want to be able to prevent the user from modifying a specific property. By setting ReadOnly(true) within my class (as you can see in the example above), all Value properties will be disabled on a class-level.
After some research I found the following solution which gives me the opportunity to enable/disable a specific property at runtime:
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)["Value"];
ReadOnlyAttribute attr =
(ReadOnlyAttribute)descriptor.Attributes[typeof(ReadOnlyAttribute)];
FieldInfo isReadOnly = attr.GetType().GetField(
"isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
isReadOnly.SetValue(attr, false);
This approach works just fine but unfortunately also on class-level only. This means if I set the Value's isReadOnly to false, all of my Parameter-objects have the Value property writeable. But I want this ONLY on that one particular object (thus object-level). I really don't want to create separate classes for read/write and readonly properties.
As I am running out of ideas, your help is much appreciated :)
Thanks in advance!
EDIT: I need the readonly properties to be grayed-out, so the user can see that it's not allowed or possible to edit them.
EDIT: Linked article has been removed (I hope just temporary). You can fine a viable alternative in answers to How to add property-level Attribute to the TypeDescriptor at runtime?. Basically you have to add (at run-time) ReadOnlyAttribute through a TypeDescriptor for that property.
Take a look at this old but nice article on CodeProject, it contains a lot of useful tools for the PropertyGrid.
Basically you provide a class or a delegate that will be used to get the attributes of your properties. Because it will be invoked passing the instance of the object you want to get attributes for then you'll be able to return (or not) the ReadOnlyAttribute with a per object basis. Shortly: apply a PropertyAttributesProviderAttribute to your property, write your own provider and replace attributes from the PropertyAttributes collection based on the object itself (and not on the class)
You can wrap the object with a custom type descriptor, but I think that would be overkill, because you have to create a new typedescriptor-derived class.
So, a simplest solution would be to have a flag, something like:
public class Parameter
{
private string thevalue;
[Browsable(false)]
public bool CanEditValue { get; set; }
[Description("the name")]
public string Name { get; set; }
[Description("the description")]
public string Description { get; set; }
[Description("the value"), ReadOnly(true)]
public string Value {
get { return this.thevalue; }
set { if (this.CanEditValue) this.thevalue = value; }
}
}
I have a class with a set of properties As given below.
class ContactInfo
{
[ReadOnly(true)]
[Category("Contact Info")]
public string Mobile { get; set; }
[Category("Contact Info")]
public string Name{ get; set; }
}
The objects of this class is being assigned to a property grid, so that the users can update an existing contact. you can see that Mobile is marked as ReadOnly.
But, when I want to add an entirely new Contact, I would want the users to be able to edit the contact Mobile also. For that I need to remove the Readonly property dynamically from the Type, before assigning the object to the property grid. Is it possible?
You can not remove the attribute at runtime, but you can use reflection to change the ReadOnly attribute's ReadOnly private backing field to False. Making it the equivalent of [ReadOnly(false)]
See this article for details:
http://codinglight.blogspot.com/2008/10/changing-attribute-parameters-at.html
Edit: fixed link
I have to agree w/ Omu; you're really talking about two classes (view models) in this case, to support your two different views. Something like
CreateContactViewModel and EditContactViewModel
it's not possible at the moment to remove attributes dinamycally (at runtime)
as a suggestion you can do 2 classes: one with the attributes and one without
The CodingLight.com blog moved to blogspot (the above link is broken).
See http://codinglight.blogspot.com/2008/10/changing-attribute-parameters-at.html.
Moreover, SysAdmin's followup did not mention the [RefreshProperties(RefreshProperties.All)] attribute that seems to be necessary for an actually-working solution.
Finally, I believe that even David Morton (author of the quoted article) missed one very important thing: if the class (ContactInfo, in SysAdmin's followup example) does not have at least one property with the [ReadOnly] attribute defined at compile time, then when the "isReadOnly" FieldInfo is set to true at runtime the result is that the whole class turns read-only.
I followed up the suggestion by Legenden. Here is what I came up with
class ContactInfo
{
[ReadOnly(true)]
[Category("Contact Info")]
public string Mobile { get; set; }
[Category("Contact Info")]
public string Name{ get; set; }
public void SetMobileEdit(bool allowEdit)
{
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this.GetType())["Mobile"];
ReadOnlyAttribute attrib = (ReadOnlyAttribute)descriptor.Attributes[typeof(ReadOnlyAttribute)];
FieldInfo isReadOnly = attrib.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
isReadOnly.SetValue(attrib, !allowEdit);
}
}
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;
//....
}