473,503 Members | 2,105 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

How to emulate missing property in object

I'm implementing entity object which should populate its properties from
database when property is first referenced.

In RDL reports I use object properties like

MyObject.MyProperty

MyObject is instance of MyEntity class. There is no MyProperty property in
MyObject at design time.

So I need to catch missing property reference and provide its value at run
time.
Something line

public class MyEntity {
override exception MissingPropertyGetException {
return dbo.ExecuteScalar("SELECT "+Exception.UnreferencedPropertyName+
" FROM myEntity");
}
}

Any idea how to implement this ?

Andrus.
May 1 '07 #1
11 3943
If RDL uses standard data-binding via the component model (which I
would expect for compatibility with DataTable etc), then perhaps look
into ICustomTypeDescriptor (1.1 onwards) on TypeDescriptionProvider
(2.0 onwards); you can provide your own runtime properties that can
bear as little or as much resemblance as you choose to the class
properties (although reflection is the default).

Marc
May 1 '07 #2
As an example of TypeDescriptionProvider, perhaps look here:

http://www.codeproject.com/csharp/Hy...Descriptor.asp

Forget about all the Reflection.Emit stuff (that is way off topic);
the important bit is the override of
CustomTypeDescriptor.GetProperties(); get hold of the original set
from "base", copy into a list, add your new dummy properties and push
the list into a new PropertyDescriptionCollection.

Marc
May 1 '07 #3
the important bit is the override of CustomTypeDescriptor.GetProperties();
get hold of the original set from "base", copy into a list, add your new
dummy properties and push the list into a new
PropertyDescriptionCollection.
Marc,

thank you for excellent information.
I found that I need to emulate static method call since FYIReporting engine
does not allow to use properties in reports.

I'm new to C# so I created testcase below based on your article.

How to catch MyStaticMethod call in HyperTypeDescriptionProvider class and
return string "test" ?
Andrus.

using System.ComponentModel;

using System;

using System.Reflection;

static class Program {

static void Main() {

Type t = typeof(MyEntity);

MethodInfo mInfo = t.GetMethod("MyStaticMethod");

Object returnVal = mInfo.Invoke(t, null);

System.Windows.Forms.MessageBox.Show(returnVal.ToS tring());

}

}

[TypeDescriptionProvider(typeof(HyperTypeDescriptio nProvider))]

class MyEntity {

// I need to emulate the following method:

// public static string MyStaticMethod() { return "test"; }

}

sealed class HyperTypeDescriptionProvider : TypeDescriptionProvider {

// How to catch MyStaticMethod call and return string "test" ?

}

May 1 '07 #4
I'm pretty sure that the component model cover neither statics not
methods, being oriented towards instance methods.

However, I'm also very confused generally; you started off talking
about RDL and properties... now, I've used RDL to generate reports
from OO data, and it worked just fine, with values hanging off
instance properties.

Sorry to be a pain, but can you clarify (again) exactly what you are
trying to do? I may be ablt to knock up a test case... Because I'm
really not sure that static methods are the way to go here!

Marc

May 2 '07 #5
Long post warning!

OK; I threw together a "from first principles" example of a
strongly-typed bindable (both via properties and
INotifyPropertyChanged) property-bag implementation using .Net 2.0
principles, and a trivial winform harness. I'd be interested to know
if this (with suitable property definitions) works with your RDL...

Note that this is a *simplified* version of such, as it only supports
a single type. In production code I would expect Bag to act as a
base-class, and as such a few changes would have to be made to
identify the correct (current) type (rather than using typeof(Bag)).

Marc

using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(fals e);

Bag.AddProperty<int>("TestProp", new
DefaultValueAttribute(5));
Bag.AddProperty<string>("Name");

Bag bag = new Bag();
using (Form form = new Form())
using (Button b1 = new Button())
using (Label l1 = new Label())
using (Label l2 = new Label()) {
form.DataBindings.Add("Text", bag, "Name");
l1.DataBindings.Add("Text", bag, "Name");
l2.DataBindings.Add("Text", bag, "TestProp");
b1.Dock = l1.Dock = l2.Dock = DockStyle.Top;
b1.Text = "Update name";
b1.Click += delegate {
TypeDescriptor.GetProperties(bag)["Name"].SetValue(bag,
DateTime.Now.ToLongTimeString());
};
form.Controls.AddRange(new Control[] { b1, l1, l2 });
form.ShowDialog();
}
}
}

interface IBag {
void OnAfterValueChanged(string propertyName);
void AddHandler(object key, EventHandler value);
void RemoveHandler(object key, EventHandler value);
void OnEvent(object key);
IBagValue GetValue(string propertyName);
}
interface IBagValue {
void ResetValue();
bool IsDefaultValue { get;}
object Value { get; set;}
event EventHandler ValueChanged;
}
interface IBagDefinition {
IBagValue Create(IBag bag);
PropertyDescriptor Property { get;}
}
sealed class BagDefinition<T: IBagDefinition {
private readonly PropertyDescriptor property;
public PropertyDescriptor Property { get { return property; } }
private readonly T defaultValue;
public T DefaultValue { get { return defaultValue; } }
public string Name { get { return Property.Name; } }
IBagValue IBagDefinition.Create(IBag bag) {
return new BagValue<T>(bag, this);
}
public BagDefinition(string propertyName, Attribute[] attributes)
{
defaultValue = default(T);
if (attributes != null) { // check for a default value
foreach (Attribute attrib in attributes) {
DefaultValueAttribute defAttrib = attrib as
DefaultValueAttribute;
if (defAttrib != null) {
defaultValue = (T)defAttrib.Value;
break;
}
}
}
property = new BagPropertyDescriptor(propertyName,
attributes);
}
internal class BagPropertyDescriptor : PropertyDescriptor {
public BagPropertyDescriptor(string name, Attribute[]
attributes) : base(name, attributes) { }
private IBagValue GetBagValue(object component) {
return ((IBag)component).GetValue(Name);
}
public override object GetValue(object component) {
return GetBagValue(component).Value;
}
public override void SetValue(object component, object value)
{
GetBagValue(component).Value = value;
}
public override Type ComponentType {
get { return typeof(Bag); }
}
public override Type PropertyType {
get { return typeof(T); }
}
public override bool IsReadOnly {
get { return false; }
}
public override bool CanResetValue(object component) {
return true;
}
public override void ResetValue(object component) {
GetBagValue(component).ResetValue();
}
public override bool ShouldSerializeValue(object component) {
return !GetBagValue(component).IsDefaultValue;
}
public override bool SupportsChangeEvents {
get { return true; }
}
public override void AddValueChanged(object component,
EventHandler handler) {
GetBagValue(component).ValueChanged += handler;
}
public override void RemoveValueChanged(object component,
EventHandler handler) {
GetBagValue(component).ValueChanged -= handler;
}

}
}
sealed class BagValue<T: IBagValue, ITypeDescriptorContext {
private T value;
private readonly IBag bag;
void IBagValue.ResetValue() {
Value = Definition.DefaultValue;
}
bool IBagValue.IsDefaultValue {
get { return EqualityComparer<T>.Default.Equals(Value,
Definition.DefaultValue); }
}
private readonly BagDefinition<Tdefinition;
public IBag Bag { get { return bag; } }
public BagDefinition<TDefinition { get { return definition; } }
public BagValue(IBag bag, BagDefinition<Tdefinition) {
if (bag == null) throw new ArgumentNullException("bag");
if (definition == null) throw new
ArgumentNullException("definition");
this.bag = bag;
this.definition = definition;
Value = Definition.DefaultValue;
}
public T Value {
get { return value; }
set {
if (EqualityComparer<T>.Default.Equals(Value, value))
return;
this.value = value;
Bag.OnAfterValueChanged(Definition.Name);
Bag.OnEvent(Definition);
}
}
public event EventHandler ValueChanged {
add { Bag.AddHandler(Definition, value); }
remove { Bag.RemoveHandler(Definition, value); }
}
object IBagValue.Value {
get { return Value; }
set { Value = (T) value; }
}

IContainer ITypeDescriptorContext.Container { get { return
null; } }
object ITypeDescriptorContext.Instance { get { return Bag; } }
void ITypeDescriptorContext.OnComponentChanged() {
Bag.OnAfterValueChanged(Definition.Name); }
bool ITypeDescriptorContext.OnComponentChanging() { return true; }
PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { get
{return Definition.Property;} }
object IServiceProvider.GetService(Type serviceType) { return
null; }
}

sealed class Bag : IBag, INotifyPropertyChanged {
private EventHandlerList events;
void IBag.AddHandler(object key, EventHandler handler) {
AddHandler(key, handler);
}
void IBag.RemoveHandler(object key, EventHandler handler) {
RemoveHandler(key, handler);
}
void IBag.OnEvent(object key) {
OnEvent(key);
}
private void AddHandler(object key, Delegate handler) {
if (handler == null) return;
if (events == null) events = new EventHandlerList();
events.AddHandler(key, handler);
}
private void RemoveHandler(object key, Delegate handler) {
if (events == null || handler == null) return;
events.RemoveHandler(key, handler);
}
private void OnEvent(object key) {
if (events == null) return;
EventHandler handler = events[key] as EventHandler;
if (handler != null) handler(this, EventArgs.Empty);
}
public event PropertyChangedEventHandler PropertyChanged {
add { AddHandler(EVENT_PropertyChanged, value); }
remove { RemoveHandler(EVENT_PropertyChanged, value); }
}
private static readonly object EVENT_PropertyChanged = new
object();
private void OnPropertyChanged(string propertyName) {
if (events == null) return;
PropertyChangedEventHandler handler =
events[EVENT_PropertyChanged] as PropertyChangedEventHandler;
if (handler != null) handler(this, new
PropertyChangedEventArgs(propertyName));
}
void IBag.OnAfterValueChanged(string propertyName) {
OnPropertyChanged(propertyName);
}
IBagValue IBag.GetValue(string propertyName) {
return GetValue(propertyName);
}
private readonly Dictionary<string, IBagValuevalues =
new Dictionary<string,
IBagValue>(StringComparer.InvariantCulture);
private IBagValue GetValue(string propertyName) {
lock (values) {
IBagValue value;
if (!values.TryGetValue(propertyName, out value)) {
value = CreateValue(this, propertyName);
values.Add(propertyName, value);
}
return value;
}
}

static readonly Dictionary<string, IBagDefinitiondefintions =
new Dictionary<string,
IBagDefinition>(StringComparer.InvariantCulture);

public static void AddProperty<T>(string propertyName, params
Attribute[] attributes) {
BagDefinition<Tdef = new BagDefinition<T>(propertyName,
attributes);
lock (defintions) {
defintions.Add(propertyName, def);
BagDescriptionProvider.ResetProperties();
}
}
internal static PropertyDescriptorCollection GetProperties() {
lock (defintions) {
PropertyDescriptor[] props = new
PropertyDescriptor[defintions.Count];
int i = 0;
foreach (IBagDefinition def in defintions.Values) {
props[i++] = def.Property;
}
return new PropertyDescriptorCollection(props, true);
}
}
static IBagValue CreateValue(IBag bag, string propertyName) {
lock (defintions) {
return defintions[propertyName].Create(bag);
}
}

public Bag() { }
static Bag() {
BagDescriptionProvider.Initialize();
}

}

sealed class BagDescriptionProvider : TypeDescriptionProvider {
static readonly BagTypeDescriptor descriptor;

[MethodImpl(MethodImplOptions.NoInlining)]
internal static void Initialize() { } // to force static ctor
static BagDescriptionProvider() {
ICustomTypeDescriptor parent =
TypeDescriptor.GetProvider(typeof(Bag)).GetTypeDes criptor(typeof(Bag));
descriptor = new BagTypeDescriptor(parent);
TypeDescriptor.AddProvider(new BagDescriptionProvider(),
typeof(Bag));
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type
objectType, object instance) {
return descriptor;
}
internal static void ResetProperties() {
descriptor.ResetProperties();
}
}
sealed class BagTypeDescriptor : CustomTypeDescriptor {
public BagTypeDescriptor(ICustomTypeDescriptor parent)
: base(parent) {
if (parent == null) throw new ArgumentNullException("parent");
}
private PropertyDescriptorCollection properties;
internal void ResetProperties() {
properties = null;
}
public override PropertyDescriptorCollection
GetProperties(Attribute[] attributes) {
return GetProperties();
}
public override PropertyDescriptorCollection GetProperties() {
if (properties == null) {
properties = Bag.GetProperties();
}
return properties;
}
}


May 2 '07 #6
I'm pretty sure that the component model cover neither statics not
methods, being oriented towards instance methods.
I can use instance methods also, if static method emulation is not possible.
I can also use properties but this requires changing RDLEngine, i'm not sure
I have enough knowledge for it chaning.
However, I'm also very confused generally; you started off talking
about RDL and properties... now, I've used RDL to generate reports
from OO data, and it worked just fine, with values hanging off
instance properties.

Sorry to be a pain, but can you clarify (again) exactly what you are
trying to do? I may be ablt to knock up a test case... Because I'm
really not sure that static methods are the way to go here!
Marc,

I'm creating Winforms application which uses MS ReportViewer control in
local mode and also www.fyireporting.com RDLViewer and Designer .
I'm try make RDLDesigner and MS Report Designer more usable for end users
for creating invoice layouts and other reports.

I want to allow users to use any field from some one row tables in report
expressions.
Those one row tables contain current company information, current user
information, current workplace information, current POS information
(separate table for each entity).

Table field name may be not know at application design time since users can
add fields to tables at run time.

My idea is:

1. Create classes Company, User, Computer, POS in some dll.
2. Add dll containing those classes to to report
3. Use classes in report expressionis like

Company.Name()

Company.CompanySpecialField()

4. Method CompanySpecialField() is not defined in Company class.
I need to catch call to CompanySpecialField() and al other unknown methods
and return field value from database by executing

ExecuteScalar("SELECT CompanySpecialField FROM Company")

I can use Company.Get("Name") but this syntax is to much typing

So I'm looking a way to use

Company.CompanySpecialField()

or if this is not possible use instance method

Code.Company.CompanySpecialField()

or use static property (this requires rdl engine changing but would be best
since contains fewes number of characters)

Company.CompanySpecialField

or even use instance property

Code.Company.CompanySpecialField
Andrus.

May 2 '07 #7
Marc,

thank you very much for this code.

I'm confused.

Is this only way to to too much code for dynamicproperty adding ?

I looked into into it at found that this requires that property must be
added to object before calling it.

How to trap nonexisting property calling action and add property in this
case by class itself ?

Andrus.

"Marc Gravell" <ma**********@gmail.comwrote in message
news:%2***************@TK2MSFTNGP06.phx.gbl...
Long post warning!

OK; I threw together a "from first principles" example of a strongly-typed
bindable (both via properties and INotifyPropertyChanged) property-bag
implementation using .Net 2.0 principles, and a trivial winform harness.
I'd be interested to know if this (with suitable property definitions)
works with your RDL...

Note that this is a *simplified* version of such, as it only supports a
single type. In production code I would expect Bag to act as a base-class,
and as such a few changes would have to be made to identify the correct
(current) type (rather than using typeof(Bag)).

Marc

using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(fals e);

Bag.AddProperty<int>("TestProp", new DefaultValueAttribute(5));
Bag.AddProperty<string>("Name");

Bag bag = new Bag();
using (Form form = new Form())
using (Button b1 = new Button())
using (Label l1 = new Label())
using (Label l2 = new Label()) {
form.DataBindings.Add("Text", bag, "Name");
l1.DataBindings.Add("Text", bag, "Name");
l2.DataBindings.Add("Text", bag, "TestProp");
b1.Dock = l1.Dock = l2.Dock = DockStyle.Top;
b1.Text = "Update name";
b1.Click += delegate {
TypeDescriptor.GetProperties(bag)["Name"].SetValue(bag,
DateTime.Now.ToLongTimeString());
};
form.Controls.AddRange(new Control[] { b1, l1, l2 });
form.ShowDialog();
}
}
}

interface IBag {
void OnAfterValueChanged(string propertyName);
void AddHandler(object key, EventHandler value);
void RemoveHandler(object key, EventHandler value);
void OnEvent(object key);
IBagValue GetValue(string propertyName);
}
interface IBagValue {
void ResetValue();
bool IsDefaultValue { get;}
object Value { get; set;}
event EventHandler ValueChanged;
}
interface IBagDefinition {
IBagValue Create(IBag bag);
PropertyDescriptor Property { get;}
}
sealed class BagDefinition<T: IBagDefinition {
private readonly PropertyDescriptor property;
public PropertyDescriptor Property { get { return property; } }
private readonly T defaultValue;
public T DefaultValue { get { return defaultValue; } }
public string Name { get { return Property.Name; } }
IBagValue IBagDefinition.Create(IBag bag) {
return new BagValue<T>(bag, this);
}
public BagDefinition(string propertyName, Attribute[] attributes) {
defaultValue = default(T);
if (attributes != null) { // check for a default value
foreach (Attribute attrib in attributes) {
DefaultValueAttribute defAttrib = attrib as
DefaultValueAttribute;
if (defAttrib != null) {
defaultValue = (T)defAttrib.Value;
break;
}
}
}
property = new BagPropertyDescriptor(propertyName, attributes);
}
internal class BagPropertyDescriptor : PropertyDescriptor {
public BagPropertyDescriptor(string name, Attribute[] attributes) :
base(name, attributes) { }
private IBagValue GetBagValue(object component) {
return ((IBag)component).GetValue(Name);
}
public override object GetValue(object component) {
return GetBagValue(component).Value;
}
public override void SetValue(object component, object value) {
GetBagValue(component).Value = value;
}
public override Type ComponentType {
get { return typeof(Bag); }
}
public override Type PropertyType {
get { return typeof(T); }
}
public override bool IsReadOnly {
get { return false; }
}
public override bool CanResetValue(object component) {
return true;
}
public override void ResetValue(object component) {
GetBagValue(component).ResetValue();
}
public override bool ShouldSerializeValue(object component) {
return !GetBagValue(component).IsDefaultValue;
}
public override bool SupportsChangeEvents {
get { return true; }
}
public override void AddValueChanged(object component, EventHandler
handler) {
GetBagValue(component).ValueChanged += handler;
}
public override void RemoveValueChanged(object component,
EventHandler handler) {
GetBagValue(component).ValueChanged -= handler;
}

}
}
sealed class BagValue<T: IBagValue, ITypeDescriptorContext {
private T value;
private readonly IBag bag;
void IBagValue.ResetValue() {
Value = Definition.DefaultValue;
}
bool IBagValue.IsDefaultValue {
get { return EqualityComparer<T>.Default.Equals(Value,
Definition.DefaultValue); }
}
private readonly BagDefinition<Tdefinition;
public IBag Bag { get { return bag; } }
public BagDefinition<TDefinition { get { return definition; } }
public BagValue(IBag bag, BagDefinition<Tdefinition) {
if (bag == null) throw new ArgumentNullException("bag");
if (definition == null) throw new
ArgumentNullException("definition");
this.bag = bag;
this.definition = definition;
Value = Definition.DefaultValue;
}
public T Value {
get { return value; }
set {
if (EqualityComparer<T>.Default.Equals(Value, value)) return;
this.value = value;
Bag.OnAfterValueChanged(Definition.Name);
Bag.OnEvent(Definition);
}
}
public event EventHandler ValueChanged {
add { Bag.AddHandler(Definition, value); }
remove { Bag.RemoveHandler(Definition, value); }
}
object IBagValue.Value {
get { return Value; }
set { Value = (T) value; }
}

IContainer ITypeDescriptorContext.Container { get { return null; } }
object ITypeDescriptorContext.Instance { get { return Bag; } }
void ITypeDescriptorContext.OnComponentChanged() {
Bag.OnAfterValueChanged(Definition.Name); }
bool ITypeDescriptorContext.OnComponentChanging() { return true; }
PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { get
{return Definition.Property;} }
object IServiceProvider.GetService(Type serviceType) { return null; }
}

sealed class Bag : IBag, INotifyPropertyChanged {
private EventHandlerList events;
void IBag.AddHandler(object key, EventHandler handler) {
AddHandler(key, handler);
}
void IBag.RemoveHandler(object key, EventHandler handler) {
RemoveHandler(key, handler);
}
void IBag.OnEvent(object key) {
OnEvent(key);
}
private void AddHandler(object key, Delegate handler) {
if (handler == null) return;
if (events == null) events = new EventHandlerList();
events.AddHandler(key, handler);
}
private void RemoveHandler(object key, Delegate handler) {
if (events == null || handler == null) return;
events.RemoveHandler(key, handler);
}
private void OnEvent(object key) {
if (events == null) return;
EventHandler handler = events[key] as EventHandler;
if (handler != null) handler(this, EventArgs.Empty);
}
public event PropertyChangedEventHandler PropertyChanged {
add { AddHandler(EVENT_PropertyChanged, value); }
remove { RemoveHandler(EVENT_PropertyChanged, value); }
}
private static readonly object EVENT_PropertyChanged = new object();
private void OnPropertyChanged(string propertyName) {
if (events == null) return;
PropertyChangedEventHandler handler = events[EVENT_PropertyChanged]
as PropertyChangedEventHandler;
if (handler != null) handler(this, new
PropertyChangedEventArgs(propertyName));
}
void IBag.OnAfterValueChanged(string propertyName) {
OnPropertyChanged(propertyName);
}
IBagValue IBag.GetValue(string propertyName) {
return GetValue(propertyName);
}
private readonly Dictionary<string, IBagValuevalues =
new Dictionary<string, IBagValue>(StringComparer.InvariantCulture);
private IBagValue GetValue(string propertyName) {
lock (values) {
IBagValue value;
if (!values.TryGetValue(propertyName, out value)) {
value = CreateValue(this, propertyName);
values.Add(propertyName, value);
}
return value;
}
}

static readonly Dictionary<string, IBagDefinitiondefintions =
new Dictionary<string,
IBagDefinition>(StringComparer.InvariantCulture);

public static void AddProperty<T>(string propertyName, params
Attribute[] attributes) {
BagDefinition<Tdef = new BagDefinition<T>(propertyName,
attributes);
lock (defintions) {
defintions.Add(propertyName, def);
BagDescriptionProvider.ResetProperties();
}
}
internal static PropertyDescriptorCollection GetProperties() {
lock (defintions) {
PropertyDescriptor[] props = new
PropertyDescriptor[defintions.Count];
int i = 0;
foreach (IBagDefinition def in defintions.Values) {
props[i++] = def.Property;
}
return new PropertyDescriptorCollection(props, true);
}
}
static IBagValue CreateValue(IBag bag, string propertyName) {
lock (defintions) {
return defintions[propertyName].Create(bag);
}
}

public Bag() { }
static Bag() {
BagDescriptionProvider.Initialize();
}

}

sealed class BagDescriptionProvider : TypeDescriptionProvider {
static readonly BagTypeDescriptor descriptor;

[MethodImpl(MethodImplOptions.NoInlining)]
internal static void Initialize() { } // to force static ctor
static BagDescriptionProvider() {
ICustomTypeDescriptor parent =
TypeDescriptor.GetProvider(typeof(Bag)).GetTypeDes criptor(typeof(Bag));
descriptor = new BagTypeDescriptor(parent);
TypeDescriptor.AddProvider(new BagDescriptionProvider(),
typeof(Bag));
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type
objectType, object instance) {
return descriptor;
}
internal static void ResetProperties() {
descriptor.ResetProperties();
}
}
sealed class BagTypeDescriptor : CustomTypeDescriptor {
public BagTypeDescriptor(ICustomTypeDescriptor parent)
: base(parent) {
if (parent == null) throw new ArgumentNullException("parent");
}
private PropertyDescriptorCollection properties;
internal void ResetProperties() {
properties = null;
}
public override PropertyDescriptorCollection GetProperties(Attribute[]
attributes) {
return GetProperties();
}
public override PropertyDescriptorCollection GetProperties() {
if (properties == null) {
properties = Bag.GetProperties();
}
return properties;
}
}
May 2 '07 #8
Nobody ever said that working with dynamic properties would be easy
;-p
If you want easy, then see if you can declare a DataTable and throw
that at your RDL; the resultant DataView works very similarly, but
much less code (but it instance oriented rather than type oriented).

As for detecting non-existant properties... you don't want a lot, eh?

The following changes appear to work, but it is stepping a little bit
away from the centre-line IMO (obviously you'd need to figure out how
to define the property; I went for a basic "object")

public static PropertyDescriptor AddProperty<T>(string
propertyName, params Attribute[] attributes) {
BagDefinition<Tdef = new BagDefinition<T>(propertyName,
attributes);
lock (defintions) {
defintions.Add(propertyName, def);
BagDescriptionProvider.ResetProperties();
}
return def.Property;
}

internal static PropertyDescriptorCollection GetProperties() {
lock (defintions) {
PropertyDescriptor[] props = new
PropertyDescriptor[defintions.Count];
int i = 0;
foreach (IBagDefinition def in defintions.Values) {
props[i++] = def.Property;
}
return new PhantomPropertyDescriptorCollection(props,
false);
}
}

internal sealed class PhantomPropertyDescriptorCollection :
PropertyDescriptorCollection {
public
PhantomPropertyDescriptorCollection(PropertyDescri ptor[] properties,
bool readOnly)
: base(properties, readOnly) {
}
public override PropertyDescriptor Find(string name, bool
ignoreCase) {
PropertyDescriptor prop = base.Find(name, ignoreCase);
if (prop == null) {
prop = AddProperty<object>(name);
Add(prop);
}
return prop;
}
}
>

May 2 '07 #9
The following changes appear to work

Mark,

Thank you.
I created a test sample.
However,

System.Reflection.PropertyInfo p = bag.GetType().GetProperty("test");

assigns null to p.
I think I'm missing something simple.
What I'm doing wrong ?

How to simplify this code ?
How to assign some string to property test so that Messagebox outputs string
?

Dynamic property implementation like this in Python requires only few lines
of code.
Any idea how to implement static property or method emulation ?

Andrus.
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

static class Program {
[STAThread]
static void Main() {
Bag bag = new Bag();
// the following line assigns null to p. Why ?
System.Reflection.PropertyInfo p = bag.GetType().GetProperty("test");

System.Windows.Forms.MessageBox.Show(p.GetValue(ba g,null ).ToString());
}
}

interface IBag {
void OnAfterValueChanged(string propertyName);
void AddHandler(object key, EventHandler value);
void RemoveHandler(object key, EventHandler value);
void OnEvent(object key);
IBagValue GetValue(string propertyName);
}

interface IBagValue {
void ResetValue();
bool IsDefaultValue { get;}
object Value { get; set;}
event EventHandler ValueChanged;
}

interface IBagDefinition {
IBagValue Create(IBag bag);
PropertyDescriptor Property { get;}
}

sealed class BagDefinition<T: IBagDefinition {
private readonly PropertyDescriptor property;
public PropertyDescriptor Property { get { return property; } }
private readonly T defaultValue;
public T DefaultValue { get { return defaultValue; } }
public string Name { get { return Property.Name; } }

IBagValue IBagDefinition.Create(IBag bag) {
return new BagValue<T>(bag, this);
}

public BagDefinition(string propertyName, Attribute[] attributes) {
defaultValue = default(T);
if (attributes != null) { // check for a default value
foreach (Attribute attrib in attributes) {
DefaultValueAttribute defAttrib = attrib as
DefaultValueAttribute;
if (defAttrib != null) {
defaultValue = (T)defAttrib.Value;
break;
}
}
}
property = new BagPropertyDescriptor(propertyName, attributes);
}
internal class BagPropertyDescriptor : PropertyDescriptor {
public BagPropertyDescriptor(string name, Attribute[] attributes)
: base(name, attributes) { }

private IBagValue GetBagValue(object component) {
return ((IBag)component).GetValue(Name);
}

public override object GetValue(object component) {
return GetBagValue(component).Value;
}

public override void SetValue(object component, object value) {
GetBagValue(component).Value = value;
}

public override Type ComponentType {
get { return typeof(Bag); }
}

public override Type PropertyType {
get { return typeof(T); }
}

public override bool IsReadOnly {
get { return false; }
}

public override bool CanResetValue(object component) {
return true;
}

public override void ResetValue(object component) {
GetBagValue(component).ResetValue();
}

public override bool ShouldSerializeValue(object component) {
return !GetBagValue(component).IsDefaultValue;
}
public override bool SupportsChangeEvents {
get { return true; }
}

public override void AddValueChanged(object component,
EventHandler handler) {
GetBagValue(component).ValueChanged += handler;
}

public override void RemoveValueChanged(object component,
EventHandler handler) {
GetBagValue(component).ValueChanged -= handler;
}

}
}

sealed class BagValue<T: IBagValue, ITypeDescriptorContext {
private T value;
private readonly IBag bag;
void IBagValue.ResetValue() {
Value = Definition.DefaultValue;
}
bool IBagValue.IsDefaultValue {
get {
return EqualityComparer<T>.Default.Equals(Value,
Definition.DefaultValue);
}
}
private readonly BagDefinition<Tdefinition;
public IBag Bag { get { return bag; } }
public BagDefinition<TDefinition { get { return definition; } }
public BagValue(IBag bag, BagDefinition<Tdefinition) {
if (bag == null) throw new ArgumentNullException("bag");
if (definition == null) throw new ArgumentNullException("definition");
this.bag = bag;
this.definition = definition;
Value = Definition.DefaultValue;
}

public T Value {
get { return value; }
set {
if (EqualityComparer<T>.Default.Equals(Value, value))
return;
this.value = value;
Bag.OnAfterValueChanged(Definition.Name);
Bag.OnEvent(Definition);
}
}

public event EventHandler ValueChanged {
add { Bag.AddHandler(Definition, value); }
remove { Bag.RemoveHandler(Definition, value); }
}

object IBagValue.Value {
get { return Value; }
set { Value = (T)value; }
}

IContainer ITypeDescriptorContext.Container {
get {
return null;
}
}
object ITypeDescriptorContext.Instance { get { return Bag; } }
void ITypeDescriptorContext.OnComponentChanged() {
Bag.OnAfterValueChanged(Definition.Name);
}
bool ITypeDescriptorContext.OnComponentChanging() { return true; }
PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor {
get { return Definition.Property; }
}
object IServiceProvider.GetService(Type serviceType) {
return null;
}
}

sealed class Bag : IBag, INotifyPropertyChanged {

private EventHandlerList events;
void IBag.AddHandler(object key, EventHandler handler) {
AddHandler(key, handler);
}
void IBag.RemoveHandler(object key, EventHandler handler) {
RemoveHandler(key, handler);
}
void IBag.OnEvent(object key) {
OnEvent(key);
}
private void AddHandler(object key, Delegate handler) {
if (handler == null) return;
if (events == null) events = new EventHandlerList();
events.AddHandler(key, handler);
}
private void RemoveHandler(object key, Delegate handler) {
if (events == null || handler == null) return;
events.RemoveHandler(key, handler);
}
private void OnEvent(object key) {
if (events == null) return;
EventHandler handler = events[key] as EventHandler;
if (handler != null) handler(this, EventArgs.Empty);
}
public event PropertyChangedEventHandler PropertyChanged {
add { AddHandler(EVENT_PropertyChanged, value); }
remove { RemoveHandler(EVENT_PropertyChanged, value); }
}
private static readonly object EVENT_PropertyChanged = new object();
private void OnPropertyChanged(string propertyName) {
if (events == null) return;
PropertyChangedEventHandler handler = events[EVENT_PropertyChanged] as
PropertyChangedEventHandler;
if (handler != null) handler(this, new
PropertyChangedEventArgs(propertyName));
}

void IBag.OnAfterValueChanged(string propertyName) {
OnPropertyChanged(propertyName);
}

IBagValue IBag.GetValue(string propertyName) {
return GetValue(propertyName);
}

private readonly Dictionary<string, IBagValuevalues =
new Dictionary<string, IBagValue>(StringComparer.InvariantCulture);

private IBagValue GetValue(string propertyName) {
lock (values) {
IBagValue value;
if (!values.TryGetValue(propertyName, out value)) {
value = CreateValue(this, propertyName);
values.Add(propertyName, value);
}
return value;
}
}

static readonly Dictionary<string, IBagDefinitiondefintions =
new Dictionary<string,
IBagDefinition>(StringComparer.InvariantCulture);

public static PropertyDescriptor AddProperty<T>(string propertyName,
params Attribute[] attributes) {
BagDefinition<Tdef = new BagDefinition<T>(propertyName, attributes);
lock (defintions) {
defintions.Add(propertyName, def);
BagDescriptionProvider.ResetProperties();
}
return def.Property;
}

internal static PropertyDescriptorCollection GetProperties() {
lock (defintions) {
PropertyDescriptor[] props = new PropertyDescriptor[defintions.Count];
int i = 0;
foreach (IBagDefinition def in defintions.Values) {
props[i++] = def.Property;
}
return new PhantomPropertyDescriptorCollection(props, false);
}
}

internal sealed class PhantomPropertyDescriptorCollection :
PropertyDescriptorCollection {

public PhantomPropertyDescriptorCollection(PropertyDescri ptor[]
properties, bool readOnly)
: base(properties, readOnly) {
}

public override PropertyDescriptor Find(string name, bool ignoreCase) {
PropertyDescriptor prop = base.Find(name, ignoreCase);
if (prop == null) {
prop = AddProperty<object>(name);
Add(prop);
}
return prop;
}
}

static IBagValue CreateValue(IBag bag, string propertyName) {
lock (defintions) {
return defintions[propertyName].Create(bag);
}
}

public Bag() { }
static Bag() {
BagDescriptionProvider.Initialize();
}

}

sealed class BagDescriptionProvider : TypeDescriptionProvider {
static readonly BagTypeDescriptor descriptor;

[MethodImpl(MethodImplOptions.NoInlining)]
internal static void Initialize() { } // to force static ctor
static BagDescriptionProvider() {
ICustomTypeDescriptor parent =
TypeDescriptor.GetProvider(typeof(Bag)).GetTypeDes criptor(typeof(Bag));
descriptor = new BagTypeDescriptor(parent);
TypeDescriptor.AddProvider(new BagDescriptionProvider(), typeof(Bag));
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,
object instance) {
return descriptor;
}

internal static void ResetProperties() {
descriptor.ResetProperties();
}
}

sealed class BagTypeDescriptor : CustomTypeDescriptor {
public BagTypeDescriptor(ICustomTypeDescriptor parent)
: base(parent) {
if (parent == null) throw new ArgumentNullException("parent");
}
private PropertyDescriptorCollection properties;
internal void ResetProperties() {
properties = null;
}
public override PropertyDescriptorCollection GetProperties(Attribute[]
attributes) {
return GetProperties();
}
public override PropertyDescriptorCollection GetProperties() {
if (properties == null) {
properties = Bag.GetProperties();
}
return properties;
}
}

May 2 '07 #10
PropertyInfo is reflection; it tells you what is actually defined on a
type. PropertyDescriptor is component-model, and supports virtual
properties.
May 2 '07 #11
PropertyInfo is reflection; it tells you what is actually defined on a
type. PropertyDescriptor is component-model, and supports virtual
properties.
Marc,

thank you.

As I understand from this message, ReportViewer cannot read virtual
property value.
Also there is no way to get value of virtual property in code. So I cannot
use this id reports.

I also added real property "test" to bag class.

bag.GetType().GetProperty("test");

still returns null.

Andrus.

May 3 '07 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
1329
by: 4Space | last post by:
I'm trying to write a plugin for visual studio, but I've hit a snag with a property that should be there, but kind of isn't. private bool IsProjectThemed( EnvDTE.Project project ) { try { if...
1
1740
by: windandwaves | last post by:
Hi Folk I am working with the TYPE property. I want to change that from 2 (byte) to 4 (long integer) for a field that already contains tons of data. How can I do that? The help reads: ...
8
1235
by: | last post by:
In VB6 there was a property - object. What is the similar property in .NET I am using a 3rd party COM grid object that requests the object property of another such object. e;g: Set grd.ddb =...
0
7093
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7348
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
7467
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5592
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
5021
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
3175
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
1519
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
744
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
397
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.