Today I was working on a WPF UserControl to display the current value of a few variables. I was wondering if there would be a way to dynamically add a property at runtime,this is my fix model but i want to add public string grapes{get;set} property at runtime and a value to that property.
is it possible to do? if yes then how?
public class Food
{
public string Apple { get; set; }
public string Orange { get; set; }
}
Perhaps the easiest way to achieve this is using a dictionary instead of properties... You can easily add new fruit types at runtime. .net also has support for dynamic types. Have a look at expandoObject https://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject(v=vs.110).aspx
Related
I have an requirement to render the screen (screen type : form) dynamically based on the service response (rather than defining the UI manually). I was able to successfully bind predefined properties to dynamically created textboxes & textviews. Following is the sample code that used to bind predefined property to dynamic textbox
Type myType = typeof(DynamicViewModel);
PropertyInfo myPropInfo = myType.GetProperty(nameof(dynamicProperty)); //dynamicProperty -static property in VM
var set = this.CreateBindingSet<DynamicActivity, DynamicViewModel>();
set.Bind(editText).To(myPropInfo.Name); //editText - dynamically created textbox
set.Apply();
But the code needs to be further improved by dynamically creating the no of properties - matching with the no of UI elements dynamically created.
The project is created using Xamarin.Android with MVVMCross's latest version. Please share the way to generate dynamic string(or object type) properties in viewmodels that can be binded with dynamically generated view elements(textboxes & textviews).
Thanks
There are a couple of ways to do this.
One is using Reflection as you are doing there, but you could have performance issues.
The other way is to arrange a bit the data and model you are getting from the server to be something like you can then use some Factories to build your View/VM:
So it could be:
public enum DataType
{
String,
Number,
Boolean,
List,
// and any other types that you need
}
public class OptionItemModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FieldModel
{
public DataType Type { get; set; }
public string DefaultValue { get; set; } // this is a serialized value
public List<OptionItemModel> Options { get; set; } // this only applies to DataType -> List
}
public class StructureModel
{
public List<FieldModel> Fields { get; set; }
}
So then you can have an ObservableCollection on your VM and your items can be created by a factory iterating for each one of the fields of the structure and so you can have custom Item View Models depending on the DataType of the field.
Then you can have a List on your View that uses a Template selector where you can create the Cell/Row depending on the DataType or the ItemViewModel and that would be it.
Then you can have a similar model structure to fill the values and upload them to the server.
Hope it's clear enough
I'm trying to do this:
public string LangofUser
{
get
{
return string.IsNullOrEmpty("how to get value?") ? "English" : "how to get value?";
}
set;
}
do I have to do this?
string _LangofUser
public string LangofUser
{
get
{
return string.IsNullOrEmpty(_LangofUser) ? "English" : _LangofUser;
}
set { _LangofUser = value};
}
This mixing of auto-implement and not-auto-implemented properties in C# is not possible. A property must be fully auto-implemented or a normal property.
Note: Even with a fully auto-implemented property there is no way to reference the backing field from C# source in a strongly typed manner. It is possible via reflection but that's depending on implementation details of the compiler.
As others have said, don't try to mix automatic and regular properties. Just write a regular property.
If you want to know what secret names we generate behind the scenes for hidden compiler magic, see
Where to learn about VS debugger 'magic names'
but do not rely on that; it can change at any time at our whim.
If you provide your own implementation of the property, it's not automatic any more. So yes, you need to do create the instance.
Check this question
What's the difference between encapsulating a private member as a property and defining a property without a private member?
If you want to keep the automatic property and still have a default value, why don't you initialize it in your constructor?
public class MyClass
{
public MyClass() { LangOfUser = "English"; }
public string LangOfUser { get; set; }
}
Since C# 6, you can also set a default value for a property as follows:
public class MyClass
{
public string LangOfUser { get; set; } = "English";
}
In C# itself, is there something like "attached property" used in WPF?
The short answer is no. The slightly longer answer is that this is a bit of an unfortunate story. We designed "extension properties" for C# 4 and got as far as implementing (but not testing) them when we realized, oh, wait, the thing we designed is not really compatible with WPF-style properties. Rather than redesign and reimplement the feature we ended up cutting it.
The even longer version is here:
http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx
AttachedProperties are part of the .NET Framework, not part of the C# language specification, and specifically part of the System.Activities.Presentation.Model namespace, which is WPF specific.
In WPF, an attached property allows you to do something like:
<TextBlock Grid.Row="2" Text="I know nothing about grids!" />
This would be like having a class in C# defined as:
public class TextBlock
{
public string Text { get; set; }
}
And being able to do this:
var tb = new TextBlock();
tb.Grid.Row = 2; // this line would not compile
In order to make this work, you'd need to pass a Grid object into your TextBlock class:
public class TextBlock
{
public string Text { get; set; }
public Grid Grid { get; set; }
public TextBlock(Grid grid)
{
Grid = grid;
}
}
But I don't think there's anything directly equivalent to the way attached properties work in WPF. You'd need to build it by hand.
What are you trying to accomplish?
You can use the ConditionalWeakTable<TKey, TValue> class to attach arbitrary state to an instance. You can combine it with extension methods to create a form of extension properties, but unfortunately without using the nice property syntax in C#.
I think you're thinking of getters and setters.
They are created like this:
public class Person
{
//default constructor
public Person()
{
}
private string _Name;
public string Name
{
//set the person name
set { this._Name = value; }
//get the person name
get { return this._Name; }
}
}
More on how they work here:
http://msdn.microsoft.com/en-us/library/aa287786(v=vs.71).aspx
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);
}
}
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);
}
}