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
Related
I'm learning XAF and I want to know how to access the value of a PropertyEditor to change it. I want to take the value from a PropertyEditor and put that value into another PropertyEditor's value. My code is like this:
Property Editor reserva = (PropertyEditor)((DetailView)View).FindItem("Reserva"); //This is a custom object
PropertyEditor dni = (PropertyEditor)((DetailView)View).FindItem("Dni");//This is a simple text editor
PropertyEditor dniReserva = (PropertyEditor)reserva.View.FindItem("Dni");//This is a variable from the custom object
dni.PropertyValue = dniReserva.ControlValue;
This does not work, any ideas? Thank you
Are you talking about copying the value of a non persistent property to another non persistent property? Because in any other case I believe there are more suitable ways to copy a value, working with the actual properties (here is usefull answer to help you with that)and not the editors.
If however you actually need this,I believe you could create a ViewController and use the PropertyEditor properties like this
foreach (PropertyEditor editor in ((DetailView)View).GetItems<PropertyEditor>())
{
var control = editor.Control as IntegerEdit;
if (control != null)
{
if (editor.Id == "Id" || editor.Caption == "Id")
{
control.Enabled = false;
}
}
}
Each property editor in XAF reads value from the specific property of the business object. This specificity reduces your task to copying the value of the specific property to another one.
In the ViewController, you can access the current business object using the View.CurrentObject property. Once the property is updated with an appropriate value, the new value will immediately appear in the property editor.
If the business object does not implement the INotifyPropertyChanged interface (for example, if you are using Entity Framework Code First), you may also want to call the View.Refresh method to make new values appear in the editor.
I'm building a class library that includes several custom attributes that apply to properties. Then I have methods that do certain things based on the placement of the attributes.
Now I want to build some unit tests, but how to I make the tests without creating something on the order of x^(number of attributes) classes just for testing purposes? Can I leverage metadata classes or something?
Basically I'd love for there to be a way for me to apply attributes to properties at runtime (i.e. inside the "Arrange" part of my test method), but I'm pretty sure that's impossible.
Edit
This is the reflection code I'm using to test attributes, since apparently how I'm reading them may make a difference:
bool skip = false, iip = false;
string lt = null;
SerializeAsOptions sa = SerializeAsOptions.Ids;
object[] attrs = prop.GetCustomAttributes(true);
foreach (object attr in attrs)
{
Type attrType = attr.GetType();
if (typeof(JsonIgnoreAttribute).IsAssignableFrom(attrType))
{
skip = true;
continue;
}
if (typeof(IncludeInPayload).IsAssignableFrom(attrType))
iip = ((IncludeInPayload)attr).Include;
if (typeof(SerializeAs).IsAssignableFrom(attrType))
sa = ((SerializeAs)attr).How;
if (typeof(LinkTemplate).IsAssignableFrom(attrType))
lt = ((LinkTemplate)attr).LinkTemplate;
}
if (skip) continue;
I'm adding another answer, because since you now provided some code, the old one is too broad. It's now (mostly) obvious that:
you control the attribute-reading code
you are reading the code via reflection (PropertyInfo.GetCustomAttributes)
So. Since you are using Reflection, TypeDescriptors will not help. You'd need to:
either read the attrs differently so TypeDescr can be used
dynamically generate assemblies at runtime to generate classes with properties on the fly during tests
It can be very interesting/entertaining, but it can also turn into nice amount of work. But, since you control both sides of the code, none of these two is actually needed.
First, let's trim the code to significant parts:
somemethod(PropertyInfo prop)
{
// ...
object[] attrs = prop.GetCustomAttributes(true); // read ATTRs from PROP
foreach (object attr in attrs) // scan the PROP's ATTRs
{
// check attr type, do something
}
// ...
}
The core of your problem is not:
adding/removing attributes during Arrange/Teardown part
but
forcing the loop over PROP's ATTRs to see attributes that your test specifies
Looking at the problem like this, the answer is almost obvious: your loop has to abstract from the "Read attributes" part.
object[] attributeReader(PropertyInfo prop)
{
return prop.GetCustomAttributes(true);
}
somemethod(PropertyInfo prop)
{
// ...
object[] attrs = attributeReader(prop); // read ATTRs from PROP
foreach (object attr in attrs) // scan the PROP's ATTRs
{
// check attr type, do something
}
// ...
}
Now, your processing code is independent of the way the attributes are read. Sure, in the example above that way is hardcoded. But it does not have to be. Depending on how you want/like to organize your tests, you can use many ways to replace the attributeReader method with other mechanisms.
For example, just add 'virtual' to the attributeReader and use inheritance to create a class that will enable AttributeFaking:
// original class:
virtual object[] attributeReader(PropertyInfo prop)
{
return prop.GetCustomAttributes(true);
}
// derived class:
object[] AttributesOverrides {get;set;}
override object[] attributeReader(PropertyInfo prop)
{
if(prop.Name = "ShoeSize") return AttributesOverrides; // return what I say!
return base.attributeReader(prop);
}
// your test setup
var t = ... // that DERIVED object
t.AttributesOverrides = new [] { ... } ; // attributes to use
For example, use delegates/lambdas, no inheritace
// note the attributeReader is now a field, not function
Func<PropertyInfo, object[]> attributeReader = defaultAttributeReader;
static object[] defaultAttributeReader(PropertyInfo prop)
{
return prop.GetCustomAttributes(true);
}
// and your test setup
var t = ... // that ORIGNAL object
t.attributeReader = customReaderForTheTest; // change the reader on the fly
// that's the reader-function to use in THIS TEST setup
static object[] customReaderForTheTest(PropertyInfo prop)
{
if(prop.Name = "ShoeSize") return null; // crash when I say so! muhaHAHAhaa!
return prop.GetCustomAttributes(true);
}
Both of those two examples end up with one class that is enables faking the attributes in some way, but that's not the only ways to do that. You can use IoC to inject the correct attributeReader. You can do that in any way you like - you just need to abstract from reading part and leave it 'open'.
It is not possible to really apply the attribute at runtime to an existing class, but there are at least two ways you could do something similar to it - it depends on how exactly are you reading those attributes later.
The options focus on the 'really' and 'existing class' part:
1) don't do that, just fake adding them
2) apply them on a class that does not exist yet! ;)
First option is a CustomTypeDescriptor. In its implementations, you will be able to dynamically answer to any queries about Attributes for some class that uses it (-> see virtual GetAttributes method).
This leads to first way:
Create AttributableTestObject that i.e. inherits from your ClassCompatibleWithThatAttribute etc
Create something like DynamicallyAttributedClass : CustomTypeProvider that exposes a static property similar to IEnumerable<Attribute>
override the GetAttributes and return whatever was provided by that static property
on your AttributableTestObject class set a TypeDecriptorProvider attribute pointing to provider (you've got to implement it, again) that returns DynamicallyAttributedClass
Now, using that static property you can change what the GetAttributes returns, and therefore you can dynamically change the setof attributes that are visible through typedescriptor.
And here's the catch: Not all engines/observers/readers/(..) actually care about TypeDescriptors. Some simply read the metadata right away from the Reflection. Reflection will not check the typedescriptors. It will simply return an information that the AttributableTestObject class has a TypeDecriptorProvider property. But whe nusing used the ComponentModel mechanisms, the custom list of attribues will be visible.
That reminds me that the reading mechanisms simply sit at TypeDescriptor class, see its methods. There's also AddAttribute, so maybe you can even get what you want without actually implementing the stuff I said above - Try using AddAttribute and then GetAttribute on your target Type and check the results. It may "just work". But again, it will not fool the reflection.
So, there's a second, "more hardcore" approach - dynamic classes. With System.Reflection.Emit you can dynamically generate an assembly that will contain whatever IL code you wish, and then load the assembly to the current runtime.
This gives you a unique option to simply generate a new fresh class(es) at runtime, with any contents and any attributes you like. You can use inheritance, so you can inherit from any ClassCompatibleWithThatAttributes. It's not that easy to do manually, but there are some libraries that make using the IL emitter easier.
Note that the generated types will be generated at runtime. This means that at compile-time you will not have them checked, you must generate them perfectly or face some really rarely seen Exceptions. Also, note that as the types are not known at compile-time, you cannot simply new the objects. You will have to create the objects basing on their freshly-generated Type through i.e. Activator.CreateInstance(Type).
Also, even though you can generate as much new classes as you want - if you overdo it, you probably will eventually hit some CLR limit, or at leat OutOfMemory, since the generated and loaded assemblies actually occupy space. You can overcome it with AppDomains - you can create some extra AppDomains and generate and load the assemblies inside them, and then, finally, you can unload that extra domain to release all memory and also unload any assemblies that were loaded there. But, I suppose you will not generate that much types to really need that. I'm writing about it just-in-case. Dont worry until you hit the OutOfMemory or similar.
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;
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 believe there is no human way to change any attribute or field inside an Attribute apart from doing it in the constructor. That is, short of redesigning and recompiling Visual Studio yourself. There is already a similar question posted here:
Change Attribute's parameter at runtime
but I believe the peculiarities of my problem are different enough to require a new post.
I use an enumeration to keep track of the different columns of a DataTable. I use attributes in each enumeration element to indicate the underlying type and the description -in case the .ToString() would give an "ugly" result due to the rigid set of characters that are allowed to name an enumeration element, such as "Tomato_Field" when you want "Tomato Field", and the like. This allows me to place all the related information in the same object, which is, I believe, what it should be. This way I can later create all the columns with a simple and clean foreach that cycles through the elements of the enumeration and extracts the metedata (description and type) to create each column.
Now, some of the columns are autocalculated, which means that during their creation -via DataTable Identifier.Columns.Add.(NameOfColumn,underlyingType,optional: autocalculatedString)- I need to specify a string that determines how it should be calculated. That string must use the names of other columns, which might be in the Description Attribute. The approach that looks logical is to use another attribute that holds the string, which should be built using the names of the other columns, requiring access to the metadata. Now that seems impossible in the constructor: you are forced to provide a constant string. You can't use a method or anything.
This problem could be solved if there were a way to change a property inside the attribute (lets call it AutocalculatedStringAttribute) at runtime. If you access the metadata you can retrieve the string you used at the constructor of the Attribute, and you can of course change that string. However, if you later access the metadata again that change is ignored, I believe the constructor is called every time the metadata is accessed at runtime, thus ignoring any changes.
There are, of course, dirty ways to achive what I am trying to do, but my question is specifically if there is a way to properly use attributes for this. Short of resorting to CodeDOM to recompile the whole assembly with the constructor of the AutocalculatedStringAttribute changed, a certain overkill.
Right, the metadata that's used to initialize the attribute is immutable. But you can add properties and methods to an attribute class that can run code and return relevant info after the attribute object is constructed. The data they rely on doesn't have to be stored in metadata, it can be persisted anywhere.
Of course, such code wouldn't have to be part of the attribute class implementation, it could just as well be part of the code that instantiates the attribute. Which is where it belongs.
It isn't entirely clear to me what code is consuming this attribute, and it matters...
You cannot change an attribute that is burned into the code - you can query it with reflection, but that is about it. However, in many cases you can still do interesting things - I don't know if they apply to your scenario, though:
you can subclass many attributes like [Description], [DisplayName], etc - and while you pass in a constant string (typically a key) to the .ctor, it can return (through regular C#) more flexible values - perhaps looking up the description from a resx to implement i18n
if the caller respects System.ComponentModel, you can attach attributes at runtime to types etc very easily - but much harder on individual properties, especially in the case of DataTable etc (since that has a custom descriptor model via DataView)
you can wrap things and provide your own model via ICustomTypeDescriptor / TypeDescriptionProvider / PropertyDescriptor - lots of work, but provides access to set your own attributes, or return a description (etc) outside of attributes
I don't know how much of this is suitable for your environment (perhaps show some code of what you have and what you want), but it highlights that (re the question title) yes: there are things you can do to tweak how attributes are perceived at runtime.
I wanted to post this as a comment but since I wanted to include some code I couldn't, given the 600 characters limit. This is the cleanest solution I have managed to find, although it does not include all the info to create the columns on the enum, which is my goal. I have translated every field to make it easier to follow. I am not showing some code which has an obvious use (in particular the implementations of the other custom attributes and their static methods to retrieve the metadata, assume that it works).
This gets the job done, but I would ideally like to include the information stored in the strings "instancesXExpString " and "totalInstancesString" in the Autocalculated attribute, which currently only marks the columns that have such a string. This is what I have been unable to do and what, I believe, cannot be easily accomplished via subclassing -although it is an ingenious approach, I must say.
Thanks for the two prompt replies, btw.
And without any further ado, lets get to the code:
// Form in which the DataGridView, its underlying DataTable and hence the enumeration are:
public partial class MainMenu : Form {
(...)
DataTable dt_expTable;
//Enum that should have all the info on its own... but does not:
public enum e_columns {
[TypeAttribute(typeof(int))]
Experiments = 0,
[TypeAttribute(typeof(decimal))]
Probability,
[DescriptionAttribute("Samples / Exp.")]
[TypeAttribute(typeof(int))]
SamplesXExperiment,
[DescriptionAttribute("Instances / Sample")]
[TypeAttribute(typeof(int))]
InstancesXSample,
[DescriptionAttribute("Instances / Exp.")]
[TypeAttribute(typeof(int))]
[Autocalculated()]
InstancesXExp,
[DescriptionAttribute("Total Instances")]
[TypeAttribute(typeof(long))]
[Autocalculated()]
Total_Instances
};
//These are the two strings
string instancesXExpString = "[" + DescriptionAttribute.obtain(e_columns.SamplesXExperiment) + "] * [" + DescriptionAttribute.obtain(e_columns.InstancesXMuestra) + "]";
string totalInstancesString = "[" + DescriptionAttribute.obtain(e_columns.InstancesXExp) + "] * [" + DescriptionAttribute.obtain(e_columns.Experiments) + "]";
public MainMenu() {
InitializeComponent();
(...)
}
private void MainMenu_Load(object sender, EventArgs e) {
(...)
// This is the neat foreach I refered to:
foreach (e_columns en in Enum.GetValues(typeof(e_columnas))) {
addColumnDT(en);
}
}
private void addColumnDT(Enum en) {
//*This is a custom static method for a custom attrib. that simply retrieves the description string or
//the standard .ToString() if there is no such attribute.*/
string s_columnName = DescriptionAttribute.obtain(en);
bool b_typeExists;
string s_calculusString;
Type TypeAttribute = TypeAttribute.obtain(en, out b_typeExists);
if (!b_typeExists) throw (new ArgumentNullException("Type has not been defined for one of the columns."));
if (isCalculatedColumn(DescriptionAttribute.obtain(en))) {
s_calculusString = calcString(en);
dt_expTable.Columns.Add(s_columnName, TypeAttribute, s_calculusString);
} else {
dt_expTable.Columns.Add(s_columnName, TypeAttribute);
}
}
private string calcString(Enum en) {
if (en.ToString() == e_columns.InstancessXExp.ToString()) {
return instancesXExpString;
} else if (en.ToString() == e_columns.Total_Samples.ToString()) {
return totalInstancesString;
} else throw (new ArgumentException("There is a column with the autocalculated attribute whose calculus string has not been considered."));
}
(...)
}
I hope this piece of code clarifies the situation and what I am trying to do.