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.
Related
I am building a GUI where I have two classes, Student and Graduate. Graduate is a child class of Student. The user will fill out forms to add the student to the list. In order to add said information to a view form I need to check what the selected item's type is. I have tried
if(view_list.selectedItem.GetType == Student)
but it doesn't work. How would I be able to check the type of the selected item?
In short, you'll need to compare XXX.GetType() with typeof(YOUR_TYPE).
As for the reason, if you have ever stared at the IntelliCode tips provided by Visual Studio, you should see that the function object.GetType() returns Type
However, Student or any other primitive types like int, string, etc. has type of class
You can't compare two values with different types (in this case the left hand side is of Type but the right hand side is of class)
What typeof() does is to get the Type of a class.
There are a couple of problems.
The GetType which you are trying to use is actually a method, not a property, so you need to call it as GetType().
The next is that you need to use typeof(Student) to compare.
And if view_list is a Winforms ListView, then SelectedItem should start with uppercase S
So then you code should be.
if (view_list.SelectedItem.GetType() == typeof(Student))
{
//Do your stuff
}
I need to cast like this:
/* Cast Brakets */
(Type.FromString(mystring))myObject.doSomething();
I need to get the type that I cast at runtime, in this particular case I can't use a generic "T" class or method.
Although if you had a way of changing the T-generic Type at runtime (without calling a class or method again) that would also help.
Here is a more specific version of my problem:
I have a List comboList and my GUI can add new ComboBoxes at runtime, these will automatically be put into comboList. Now there are database tables for each of those ComboBoxes in comboList. I added the name of each of the database classes in the .Tag field of each ComboBox
(example: combobox_users.Tag = "users_databaseClass")
Now at runtime I need to cast into the type of users_databaseClass for example, but it appears to me that this is impossible. It appears that this is simply not possible to put a Type into cast-brackets at runtime to actually cast that type.
Help would be greatly appreciated, I've been trying for days.
To use the properties and methods of a wacky type, you'll need a reference to that type (e.g. Type.GetType("string_name_of_type")) and you'll need some pretty cool reflection (e.g. theType.GetMethod("method_name")). Your performance won't be great. See http://msdn.microsoft.com/en-us/library/system.type.getmethod(v=vs.71).aspx
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;
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