usercontrol with readonly property that can be set at design time

M

mmcd79

Can someone tell me if it's possible to create a property for a
usercontrol, that is essentially readonly, but able to be set via the
designer before runtime?

I have a property for a control that I want to set essentially one
time. This property is basically a static property that can change at
the developer's wish, but only one time. I need to be able to
reference the property later.

I've tried setting the property to readonly, but that hides it from the
designer properties window. I've tried various attributes to no avail
(i.e. DesignOnly(true)). When I do this, I cannot set the property at
design time(the value doesn't hold). But in later code I can change
that property without fail.

I'm confused. Please help.
 
G

Guest

Not the most elegant solution, but I guess you could throw an exception if
the property is set in runtime (code not written in IDE, so not tested, and
could have syntax errors).

Public Property MyProp As Integer
Get
Return _myProp
End Get
Set(ByVal value As Integer)
If Me.DesignTime Then
_myPorp = value
Else
Throw New ApplicationException("MyPorp is readonly in runtime.")
End If
End Set
End Property

Joris
 
S

Stoitcho Goutsev \(100\)

Hi,

No attibutes will help you with that. DesignOnly attruibute won't help
because as the name suggests the values for such a property are design time
only - no code is generated in the form or user control to restore set up
such properties at runtime. The values are stored in the resource file and
are use at design time only.

If you declare the property as readonly or use readonly field it won't do
either. Don't forget that what ever you set in design time needs to be
applied in runtime and this is done in the IntializeComponent method. From
the CLR perspective this is just a method, so it has no power to set
non-writable or non-public properties and fields.

I see two solutions:
1. (that I'd suggest) is to use some variation on the Joris code.

I say variation becuse this code has one big flaw - when you run your
applicaiton the InitializeComponent will try to set the property and at this
moment DesignTime will return false and the control will throw an
exception. You should probably have some special value for this property
that will tell you whether the property is already initialized or not and
will allow to be initialized only once.

2. If you have a designer attached to your control you can shadow your
readonly property with read/write one, thus allowing users to set its value.
Then you need to supply your own CodeDomeSerializer that will generate
appropriate code to set somehow that property. Of course you need to have
some backdoor open for setting this proeprty such as an undocumented method.


There is something that bothers me though. You say that this is going to be
a static property. If it is exposed on the level of the control there might
be 2 or even more instances of your control on the form. Each of these
controls will try to set the static property. If using the first solution
you are going to get an exception as soon as the second control tries to set
it.
 
M

mmcd79

Thank you both for responding :)

I did not think this was going to be such a difficult thing to do haha.
Maybe I'm just going about it the wrong way. I'm not the most
intuitive/knowledgable coder. This is just hobby for me.

I'm essentially writing a form of a wizard. I have a navigation panel
that currently contains several labels that have click events to
control which wizard page I'm on. All of my content pages are custom
usercontrols (which make no difference here).

Ultimately I'm trying to find out which label was clicked and show the
appropriate content for each label. My previous thought was to attach
a page property for each label (which in turn makes this a custom label
with this additional property and as such the purpose behind my entire
question). Any additional customlabels added (in the future) could
just have the next page value set (by developer) and then tied to
corresponding "content page".

I don't want to do any sort of case statement based on the control
name/text as this leaves no room for growth. Any developer picking
this up after me may modify the names/text of these labels to something
more meaningful so I want the properties to at least be a little more
meaningful in terms of their purpose and lenient in terms of these
changes.

I could just do this with a normal property, but I didn't want someone
changing the page values of the controls programmatically after they
have first been set. Just trying to figure out the "best" way to do
this, not some ugly hack if at all possible.

I appreciate the assistance given thus far and look forward to more
suggestions.
 
M

mmcd79

hahaha.. I'm such a retard. I'm researching all over to find out what
the "Joris Code" is as I sitting here thinking it's some well known
coding methodology. I couldn't find anything on it. Then I think,
"Self, he mentions something that the previous poster said as well.
Low and behold his name is Joris. *sigh*

I have seen several implementations of Joris' suggestions and some of
them have had an additional property, or private member so to speak
that tracks if the property has been set or not. Wasn't sure if that'd
be a good way to go. Guess I'll give it a shot.

Thanks again!
 
M

mmcd79

I have set the following, but I'm still having an issue.
--------------------------------------------------------------------------------------------------
Public Property WizardPageNumber() As Integer
Get
Return _WizardPageNumber
End Get
Set(ByVal value As Integer)
If Me.DesignMode Then
Debug.WriteLine("we're in designmode")
'check to see if wizardpagenumber has already been set.
If so, throw exception alerting developer
'that this property can only be set once.
If Not _PageIsSet Then
_WizardPageNumber = value 'set page value
_PageIsSet = True 'set tracker variable to
prevent further setting of this value.
Else
Dim ex As New Exception("WizardPageNumber can only
be set once.")
Throw ex
End If
End If
End Set
End Property
--------------------------------------------------------------------------------------------------

If on a form I drop this control on the form, I can set the property
once via the designer. Any subsequent settings will raise an
exception. Super.

Now the problem I have is say I set the initial value to 5. Then as a
test set the property to a different value, say 3, during the form load
event. If I run a check for the value before and after setting it to
3, I get no exception, and both before and after the value is stuck at
0.

I'm assuming the inability to set the value is due to the "if
me.designmode" declaration. Any suggestions for this?
 
G

Guest

I suggest you step through the code in runtime, and you'll see what is wrong.

When not in "designmode", the value is not saved in the variable. Yo
ushould change you code as follows, to allow the property to be set in
runtime:

If Me.DesignMode orelse Not _PageIsSet Then
_WizardPageNumber = value
_PageIsSet = True
Else
Dim ex As New Exception("WizardPageNumber ....")
Throw ex
End If

Joris
 
M

mmcd79

Thanks Joris. I guess you could say that worked, although now I'm
thinking I really should do this a different way haha. The exception
works fine in the designer but it really causes some interruption
during runtime, obviously due to the exception I throw. I'd end up
having to do some exception handling in designmode vs realtime mode to
prevent total breakdown at runtime, and it's just getting too ugly.

I really appreciate the help and the insight into using
shortcircuiting. I never even thought of that. Nor did I even think
to try debugging :-x. I think it's cuz I knew the designmode if block
woulda been skipped during runtime. Denial I guess :).

Since I cannot think of an elegant solution to this I think I'm going
to just use a normal public property and let the developer know via
comment that setting this value more than once in code could wreak
havoc.

Another ugly thought, is there any way via reflection to possibly get
the calling procedure? Maybe I can limit the value to be set during
it's initialization phase so it can be set all it needs in the designer
(as it automatically generates that code), and then throw an exception
if it's tried to be set in any other procedure.

Thanks guys!
 
G

Guest

I don't think this could cause much "interruption during runtime". The
property should never be set during runtime anyway (you wanted a read-only
property), so if you do try to set it, you get an exception the very first
time you test that code, and the exception message should be meaningful to
the developer, so that he understand what is wrong. Then the developer fixes
his code, and there are no more "interruptions at runtime".

Also, you could modify the property setter to not throw an exception, but
also not modifying the value of the property if it has been set before. That
would prevent the "interruption" but it would be very confusing for the
developer who tries to set the property, does not get an exception, but
notices that it does not work the way he expected. (Maybe a "debug.Assert"
could help, but only if the code is compiled in debug mode.).

Joris
 
M

mmcd79

I probably said it wrong. I'll try to clarify what I meant. With the
code that I had, if the developer tried to set the code during design
time via the designer, the exception worked wonderfully.

If the developer tried to set the value elsewhere in code, the
exception wouldn't be thrown until runtime when the value would try to
be set.

What worries me in this scenario is say the developer set the value in
code, but in such a way that it wasn't set on load or any other
immediate time. Maybe it was a reaction to some other function that
never got called until well after the app was loaded. He may not get a
chance to "test" that functionality as the app loaded fine. The app
would be deployed and then someday as the app's being used, a horrible
exception gets thrown due to the developer's oversite.

Granted proper debugging of the entire app would help prevent this, but
most people don't do that, especially in my company. I'm trying to
prevent as much as possible since our normal "developers" aren't really
taking the time to do things right haha.

I hope that explains my worry and doubt for this method. I need a true
readonly property, but I need to be able to set it. Hopefully I'm not
just missing what you're saying.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top