I am currently trying to develop a mobile barcode reader in Windows Phone 7.5 using the ZXing library.
Seeing that I am posting here, you might already have guessed that I am facing some kind of problem that I don't know any solution to.
The problem is the following:
The ZXing library allows for multiple barcode formats - however, I'd like to include a settings menu for the user to focus on one barcode specifically.
The BarcodeFormat-object is static and contains the readonly members (of type BarcodeFormat) that I want to assign.
Seeing and hearing that Reflection is THE powerful weapon for dynamic behaviour like this, I thought I'd give it a try.
So far I have code that gets all the possible formats from ZXing using
MemberInfo[] plist = typeof(BarcodeFormat).GetMembers();
That works for getting the names of the formats, meaning I can successfully show the names in a list.
But I am running into a problem when trying to assign these formats to the actual reader, because I only have the MemberInfo and no longer the BarcodeFormat.
So far I have only found examples where the user wanted to access (set / get) variables dynamically.
The proposed solutions however did not seem to fit my problem - at least I didn't find any way to assign the format in those ways.
Any help would be great :)
Thank you very much.
EDIT:
The BarcodeFormat is used like this:
WP7BarcodeManager.ScanMode = BarcodeFormat.ITF;
In this example, only barcodes in the ITF (interleaved 2 out of 5) format would be accepted.
I have so far tried the following approaches.
Simply assign the MemberInfo object instead of the original BarcodeFormat object.
Cast the MemberInfo object to BarcodeFormat.
I tried to use FieldInfo and getValue, however it seems that I have to create an example object and assign a value to the needed field in order to get the value. This can't be done here, because the object is static and the field is readonly.
The whole ZXing library is compiled as a DLL that I link my project to. (it seems to be linked correctly, because everything else works). An example declaration of BarcodeFormat looks like this
public static readonly BarcodeFormat ITF
get ITF dynamically:
var formatName = "ITF";
var format = typeof(BarcodeFormat)
.GetProperty(formatName, BindingFlags.Static | BindingFlags.Public)
.GetValue(null, null);
set WP7BarcodeManager.ScanMode:
WP7BarcodeManager.ScanMode = (BarcodeFormat)format;
ps
member to BarcodeFormat:
var _format = member is PropertyInfo
? ((PropertyInfo)member).GetValue(null, null)
: ((FieldInfo)member).GetValue(null);
var format = (BarcodeFormat)_format;
"Because static properties belong to the type, not individual objects, get static properties by passing null as the object argument"
For Example :
PropertyInfo CurCultProp = (typeof(CultureInfo)).GetProperty("CurrentCulture");
Console.WriteLine("CurrCult: " + CurCultProp.GetValue(null,null));
So all you need to do is call GetProperties() instead of GetMembers() and call GetValue(null, null) to get the value.
I don't fully understand why you go through the hassle with reflection.
You can enumerate the bar code types like this (ok dummy code, you should probably bind to a listbox/picker but.. ):
var mgr = new BarcodeTypeManager();
foreach (var barCode in mgr.BarcodeTypes)
{
WP7BarcodeManager.ScanMode = barCode.BarcodeType;
}
(In fact, there's also a BarcodePhotoChooser picker you can use.)
And if the user can save a preferred type, you can easily look it up again:
var typeToUse = mgr.BarcodeTypes.Where(b => b.Name == "what user selected").FirstOrDefault();
WP7BarcodeManager.ScanMode = typeToUse.BarcodeType;
Related
I want to retrieve the designer-assigned values of controls, e.g. when I designed a TextBox with the .Text "Hello World", then change the .Text during runtime: How can I retrieve the String "Hello World" again during runtime?
My thoughts so far:
I can write a set-up routine and assign these "default" values in there alone, and call that method again when ever I want to reset the values.
Cons:
- Not as flexible (No way of resetting individual Controls)
- would need to write a routine for each implementation
- missing out on the convenience of just setting the values once in the designer
I would really like a static method/extension which would enable me to plug in my Control and get the values assigned to it within my class designer.
I started trying to implement an extension within my extension library, where I create a new instance of the main Form Class and grab the value from there - but that approach has obvious disadvantages:
- The Form Class may have different constructor signatures, like string[] args for applications with console arguments; creating instances of unknown signatures isn't trivial or a good idea in general
- It's a heavy weight approach; depending on the complexity of the project, you might not want to create piles of instances every time you want to get a Control's designer-assigned value.
- This would execute what ever code is in the constructor
So I'm really hoping I can use Reflection or something similar to get to the designer-assigned values.
But I have no idea how to go about looking for that; googling things like "visual .net get designer default control value" yielded no relevant results.
Can somebody point me in the right direction?
My test extension method currently looks something like this:
public static string getDefaultText(this Control c)
{
Form mainForm = Form.ActiveForm; // just a quick easy way to test this
Type t = mainForm.GetType();
var f = Activator.CreateInstance(t);
Control a = ((Form)f).Controls[c.Name]; // unfortunately, .Controls only contains direct children, not all descendants; recursive searching would be needed
return a.Text;
}
and works for what it is, which is to say a proof of concept of a bad approach :/
#Selvin commented with a good idea: Let me formulate a preliminary work-around from it.
Once the Form uses Localization (Set Localizable to True at design-time), a version of the Control that represents its state in the Designer is stored in the app's Resources.
This seems to include all designable properties (everything in the Properties panel/window) (Edit: apparently not).
Using a ComponentResourceManager (implementing ResourceManager), we can apply that state to a Control again during runtime using its method ApplyResources:
public static void resetControl<T>(this T c, string key = "") where T : Control // Using generic approach for the convenience of being able to use the Type T
{
Form f = c.FindForm();
ComponentResourceManager resources = new ComponentResourceManager(f.GetType()); // Manage the resources from our Form class
if (key == "")
{
resources.ApplyResources(c, c.Name); // Simply natively apply all resources
}
else // If we want to reset only one specific property...
{
// rather than trying to get to the data serialized away somewhere, I'm using this work-around
T r = (T)Activator.CreateInstance(c.GetType()); // create a new instance of the Control in question
resources.ApplyResources(r, c.Name);
setAttr(c, key, r.getAttr(key)); // setAttr and getAttr are helper extensions I always have on hand as well
}
}
public static void setAttr(this object o, string key, object val)
{
foreach (PropertyInfo prop in o.GetType().GetProperties())
{
string nam = prop.Name;
if (nam == key)
{
prop.SetValue(o, val);
return;
}
}
}
public static dynamic getAttr(this object o, string key)
{
Type myType = o.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo prop in props)
{
if (prop.Name == key)
{
return prop.GetValue(o, null).ChangeType(prop.PropertyType);
}
}
return null;
}
Usage:
// Reset everything to the Designer state:
textBox1.resetControl();
// Reset only the TextAlign property:
textBox1.resetControl("TextAlign");
// Reset only the Dock property:
textBox1.resetControl("Dock");
// ... etc
This works reasonably well and I can write further abstractions making the process of resetting certain values easier.
I don't like having to create a new instance of a control, but I'm willing to live with it for this work-around. However, better approaches are definitely welcome.
Update: Shortcomings
It looks like an empty .Text from Designer will not overwrite a non-blank .Text using ApplyResources, it seems.
However, using a proxy Control instance like in the case of supplying "Text" as a key string in my extension method above, this still works
It looks like it doesn't work with most Controls. Testing so far only had it work on TextBoxes, Labels and CheckBoxes with the .Text property, but not the .Checked property of the CheckBox
Attempting to reset a NumericUpDown's .Text (for example because you're carpet-bombing everything with resetting "Text" in order to reset it for those who have a relevant .Text) will set its .Value to 0
SHORT VERSION
What's the best way to use reflection to turn something like string prop = "part1.first_name"; into a System.Reflection.PropertyInfo, so that I can use the GetValue and SetValue functions?
LONG VERSION
I'm using ASP .NET MVC to build a questionnaire for my organization. It's very long, so it's divided into several different pages. Since it's not uncommon for us to get requests like, "Can you move this question to that page, and this other question to another page," I need to build this to be pretty flexible for a junior programmer to change.
My model is a complex class (it's got five member classes that have mostly primitive-typed properties on them).
So, I access it by doing things like Model.part1.first_name or Model.part2.birth_date.
Since the same model is used on all of the pages, but not all of the questions are on every page, I have ActionAttributes that essentially clear out all of the properties that were submitted on the form except for the ones that were displayed on that page (so someone can't inject a hidden field into the form and have the value persist to the database).
I want to make sure that I only save valid field values and don't let the user proceed to the next page until the current one is entirely OK, but I also want to save the values that are valid, even if the user isn't allowed to proceed.
To do this, I have a function that takes two instances of my model class, a reference to the ModelStateDictionary, and a string[] of field names like "part1.first_name" and "part2.birth_date". That function needs to copy all of the values listed in the string array that do not have validation errors from the first (ie, form-submitted) object into the second (ie, loaded from the db) object.
As stated above, what's the best way to use reflection to turn something like "part1.first_name" into a System.Reflection.PropertyInfo, OR, is there a better way to accomplish this?
var infoParts = prop.Split('.');
var myType = Type.GetType(infoParts[0]);
var myPropertyInfo = myType.GetProperty(infoParts[1]);
Assuming "part1" is your type. Although this is very limited and very dependent on the string being in the correct format and the type being in the current scope.
I would probably handle this differently, using data. I would keep, in the database, which step each question belongs to. To render that step, I would select the questions that match that step and have a model that contains a list of question id/question pairs. Each input would be identified by the question id when posted back. To validate, simply compare the set of question ids with the expected ids for that step. This way, to change which question goes in which step is to only change the data in the database.
If you do end up going down that road, you'll need to split the string into parts and recursively or iteratively find the property on the object at each step.
PropertyInfo property = null;
Type type = questionModel.GetType();
object value = questionModel;
object previousObj = null;
foreach (var part in questionId.Split('.'))
{
property = type.GetProperty(part);
previousObj = value;
value = property.GetValue(value,null);
type = value.GetType();
}
// here, if all goes well, property should contain the correct PropertyInfo and
// value should contain that property's value...and previousObj should contain
// the object that the property references, without which it won't do you much good.
Ok, I've thumped on this idea all day now, and I have reached the part where I admit I just flat out don't know. It's possible that what I'm doing is just stupid and there is a better way, but this is where my thinking has brought me.
I am attempting to use a generic method to load forms in WinForms:
protected void LoadForm<T>(ref T formToShow, bool autoLoaded) where T : FormWithWorker, new()
{
// Do some stuff
}
The forms are loaded by a ToolStripMenuItem (either through the selection of the item or using the Open Windows menu item). They are lazy-loaded, so there are fields for the forms within the MDI parent, but they are null until they are needed. I have a common method used for ToolStripMenuItem_Click that handles all of the menu item clicks. The method has no real way of knowing which form is being called for except that the name of the ToolStripMenuItem matches a pattern chosen for the form class names they correspond to. So, using the name of the ToolStripMenuItem, I can divine the name of the type of form being requested and the name of the private field allocated to store the reference for that form.
Using that, I can either use a growing/contracting switch statement with hard-coded types and string matches to call method with the specific type set (undesirable), or I can use Reflection to get the field and create the instance of the type. The problem to me is, System.Activator.CreateInstance provides an ObjectHandler that can't be cast to the types that I need. Here is a snippet of what I have so far:
string formName = "_form" + ((ToolStripMenuItem)sender).Name.Replace("ToolStripMenuItem", "");
string formType = formName.Substring(1);
FieldInfo fi = this.GetType().GetField(formName, BindingFlags.NonPublic | BindingFlags.Instance);
FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this);
if (formToLoad == null)
{
formToLoad = (????)System.Activator.CreateInstance("MyAssemblyName", formType);
}
this.LoadForm(ref formToLoad, false);
fi.SetValue(this, formToLoad);
I know the string name of the type that goes in for (????) but at compile-time I do not know the type because it changes. I have tried a bunch of ways to get this cast/instantiation to work, but none have been successful. I would very much like to know if it's possible to perform such a cast knowing the type only as a string. I tried using Type.GetType(string, string) to perform the cast, but the compiler didn't like it. If someone has a different idea on how to load the forms dynamically because I'm just doing it stupidly, please let me know about it.
This problem is usually resolved by casting to a common base class or interface of all potential types.
In C# 4, you can also assign it to a dynamic variable to hold the return value and call arbitrary methods on it. The methods will be late bound. However, I prefer to stick to the former solution whenever possible.
You'd be better off with the other overload that takes a Type and using e.g. Type.GetType(string).
FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this);
if (formToLoad == null)
{
formToLoad =
(FormWithWorker)System.Activator.CreateInstance(Type.GetType("MyNamespace.MyFormType"));
}
According to what you have, FormWithWorker must be (at least) as base class of the type you are instantiating, so you can do this:
FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this);
if (formToLoad == null)
{
formToLoad = (FormWithWorker)System.Activator.CreateInstance("MyAssemblyName", formType);
}
While a common interface is one way to approach this problem, interfaces aren't practical for all scenerioes. The decision above is one of going with a factory pattern (switch statement - concrete class selection) or use reflection. There's a stack post that tackles this problem. I believe you can directly apply this to your issue:
Method Factory - case vs. reflection
I'm trying to add Intellisense to C# code editor based on the richtextbox control. So far, I've got it parsing the entered text to find all variables and their types (works well). The drop down box works well. What I can't get is a proper list of options for the drop-down list box.
How can I get the following list, programmatically:
I have already compiled a list of variables and their types, so when the user presses . I know that I have a variable c of type Color. I just need to know what function to call to get the list I need for the drop-down box.
I've tried this code: http://www.codeproject.com/KB/cs/diy-intellisense.aspx but couldn't get it to work properly. I've also read a ton of other threads on StackOverflow to no avail. I'd really like to finish this instead of using someone elses drop-in editor component.
Any hints would be appreciated. Thanks.
If you know the type, you should be able to Reflect on the type and get all the information you need.
Type.GetMembers would probably be your best bet. You may need a second call to get any static methods as well:
var instanceMembers = typeof(Color)
.GetMembers(BindingFlags.Instance | BindingFlags.Public);
var staticMembers = typeof(Color)
.GetMembers(BindingFlags.Static | BindingFlags.Public);
Each MemberInfo object will be able to tell you the MemberType (Property, Field, Method, Event, etc.)
Just use the instanceMembers when the user types a variable (like c in your example) followed by . and use the staticMembers when the user types a type name (like Color in your example) followed by ..
Assuming you have a name table with types this should give you a decent start:
var type = _names[name].Type;
var members = type.GetMembers(); // Check context to grab private methods?
So maybe you can extend your name table to include:
Type
Context
Members
You'd want to use reflection to some degree. If you have the type, or the name of the type, you can get a Type instance.
E.g. Type.GetType("System.Int32")
Then you can call Type.GetMembers() on that Type object, see here:
http://msdn.microsoft.com/en-us/library/424c79hc.aspx
...and you'll have an array of MemberInfo objects which have the name (.Name), type of the member (.MemberType), and from that other information, like parameter lists.
Hope that helps.
Is it possible to add attributes at runtime or to change the value of an attribute at runtime?
This really depends on what exactly you're trying to accomplish.
The System.ComponentModel.TypeDescriptor stuff can be used to add attributes to types, properties and object instances, and it has the limitation that you have to use it to retrieve those properties as well. If you're writing the code that consumes those attributes, and you can live within those limitations, then I'd definitely suggest it.
As far as I know, the PropertyGrid control and the visual studio design surface are the only things in the BCL that consume the TypeDescriptor stuff. In fact, that's how they do about half the things they really need to do.
Attributes are static metadata. Assemblies, modules, types, members, parameters, and return values aren't first-class objects in C# (e.g., the System.Type class is merely a reflected representation of a type). You can get an instance of an attribute for a type and change the properties if they're writable but that won't affect the attribute as it is applied to the type.
You can't. One workaround might be to generate a derived class at runtime and adding the attribute, although this is probably bit of an overkill.
Well, just to be different, I found an article that references using Reflection.Emit to do so.
Here's the link: http://www.codeproject.com/KB/cs/dotnetattributes.aspx , you will also want to look into some of the comments at the bottom of the article, because possible approaches are discussed.
No, it's not.
Attributes are meta-data and stored in binary-form in the compiled assembly (that's also why you can only use simple types in them).
I don't believe so. Even if I'm wrong, the best you can hope for is adding them to an entire Type, never an instance of a Type.
If you need something to be able to added dynamically, c# attributes aren't the way. Look into storing the data in xml. I recently did a project that i started w/ attributes, but eventually moved to serialization w/ xml.
Why do you need to? Attributes give extra information for reflection, but if you externally know which properties you want you don't need them.
You could store meta data externally relatively easily in a database or resource file.
Like mentionned in a comment below by Deczaloth, I think that metadata is fixed at compile time. I achieve it by creating a dynamic object where I override GetType() or use GetCustomType() and writing my own type. Using this then you could...
I tried very hard with System.ComponentModel.TypeDescriptor without success. That does not means it can't work but I would like to see code for that.
In counter part, I wanted to change some Attribute values.
I did 2 functions which work fine for that purpose.
// ************************************************************************
public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName, string description)
{
PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
if (att != null)
{
var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldDescription != null)
{
fieldDescription.SetValue(att, description);
}
}
}
// ************************************************************************
public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
{
PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
if (att != null)
{
var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldDescription != null)
{
fieldDescription.SetValue(att, isReadOnly);
}
}
}
When faced with this situation, yet another solution might be questioning you code design and search for a more object-oriented way. For me, struggling with unpleasant reflection work arounds is the last resort. And my first reaction to this situation would be re-designing the code. Think of the following code, which tries to solve the problem that you have to add an attribute to a third-party class you are using.
class Employee {} // This one is third-party.
And you have code like
var specialEmployee = new Employee();
// Here you need an employee with a special behaviour and want to add an attribute to the employee but you cannot.
The solution might be extracting a class inheriting from the Employee class and decorating it with your attribute:
[SpecialAttribute]
class SpecialEmployee : Employee
{
}
When you create an instance of this new class
var specialEmployee = new SpecialEmployee();
you can distinguish this specialEmployee object from other employee objects. If appropriate, you may want to make this SpecialEmployee a private nested class.