In .:
[mono.git] / mcs / class / System.Web / Hacking.FAQ
1 Q: How do I get a question/answer added to this file?
2    
3 A: Just ask.
4
5
6 Q: How do I write that 'style' attribute?
7    
8 A: The 'style' attribute of html tags is rendered in WebControl derived classes
9    by using ControlStyle. This property is usually of type
10    System.Web.UI.WebControls.Style.  It has several properties to get/set colors,
11    font, sizes... And also a few methods like AddAttributesToRender (which is the
12    one you should call in your Render method to add the "style='blah'" after
13    BeginTag.
14
15
16 Q: Which method calls AdCreated event?
17    
18 A: As for any other events, you can just create a small test, attach
19    your own method to the event and throw an exception there. The
20    resulting page will have the stack trace either visible or in a
21    HTML comment at the bottom.
22
23
24 Q: Misc: using HtmlTextWriter
25    
26 A: Attributes added using AddAttribute will be applied to the next
27    RenderBeginTag called. So if you want <a href="lalala">...</a>, do:
28         writer.AddAttribute (HtmlTextWriterAttribute.Href, "lalala");
29         writer.RenderBeginTag (HtmlTextWriterTag.A);
30         ...
31         writer.RenderEndTag ();
32
33    Use HtmlTextWriterAttribute and HtmlTextWriterTag unless there's no value in
34    them for the attribute/tag you're writing, in which case you can just use a
35    string.
36    
37 Q: What attributes do I need on my control?
38 A: AFAIR, there are only 2 attributes that affect how controls are parsed:
39
40         * ControlBuilderAttribute: specialized parsing.
41         * ParseChildrenAttribute:
42                 [ParseChildren (false|true)]
43                 This tells the parser to consider tags inside the ones of this control
44                 as properties (true) or as child controls (false).
45                 
46                 When set to true, there's an optional second parameter that
47                 tells the name of the property that will get the new controls
48                 added. This is useful, for example, for Table, whose children
49                 are added to Rows.
50         * ValidationPropertyAttribute: it can take a property name, which will
51         be the property checked when Page.Validate() is called.
52
53    the design time attributes are not needed by now. 
54
55    For control properties, one attribute that is used sometimes is
56    TypeConverterAttribute. If a property needs this attribute and its
57    missing, you'll probably get a compilation error.
58
59    Basically you need to put:
60
61         [TypeConverter (typeof (YourConverter))]
62
63    Look at Unit.cs, UnitConveter.cs for an example
64
65 Q: How do I find out the attribute values?
66 A:
67
68 The easiest way to do this is to use the master info files from
69 corcompre. Open up:
70
71 http://mono.ximian.com/masterinfos/masterinfos-1.1.tar.gz
72
73 And go to the System.Web file. Grep for your class; the attributes and
74 their values will be there.
75    
76 Q: How do I get the source C# generated for a page/control?
77 A:
78         rm -rf /tmp/$USER-temp-aspnet
79         MONO_ASPNET_NODELETE=1 xsp
80
81    The file(s) will be in /tmp/$USER-temp-aspnet/XXXXX/*.cs.
82
83
84 Q: How do I know if an attribute value is stored in ViewState? How do I know the
85    key to be used when storing a value in ViewState?
86
87 A: ViewState is a protected property, so you need to create a class deriving
88    from the control you're testing/writing and have a method there that you can
89    call before and after setting a property value. That way you can find out the
90    key that should be used, the type of the value, the value...  Check out the tests
91    in Test/standalone/adrotator/adrotator-defaults.aspx for an example.
92
93    
94 Q: My control has a bunch of properties, but most of them are never set. Any
95    trick to improve speed when getting the default value from them?
96
97 A: You can use an int, [flags] enum, ... to keep track of which
98    properties have been set so that if someone calls get_Prop, you do
99    something like:
100
101         if (has_this_property_been_set)
102                 return (type) ViewState [key];
103
104         return DEFAULT;
105
106    where 'type' is the property type and DEFAULT is the default value
107    for the property.
108
109 Q: How do I test my code?
110
111 A: Update the System.Web_test.dll.sources with your new tests, and also
112    add the tests to the `files-to-copy' file.
113
114    Then run this:
115
116         CVS=/cvs
117         sh update-old $CVS/mcs
118         cd $CVS/mcs
119         make run-test-local
120
121 Q: My control will be handling data coming from a postback to trigger an event.
122 Do I have to do anything?
123
124 A: Yes. You'll have to register your control for this. There's a method in Page
125 called RegisterRequiresPostBack. You need to call that from OnPreRender. Don't
126 call it if the control is disabled or the Page property has not been
127 initialized. You probably want to read the next Q/A too.
128
129 Q: My control implements IPostBackDataHandler.LoadPostData and I get
130 controlname.x and controlname.y in the postback collection. How do I make the
131 Page raise a postback event?
132
133 A: You have to register your control for this, as the page will not be able to
134 map from that controlname.x/controlname.y to an actual control. To do that,
135 just run:
136
137         Page.RegisterRequiresRaiseEvent (yourcontrolhere);
138
139 In the stage where postback events are run, the page will call
140 IPostBackEventHandler.RaisePostBackEvent. Here you'll have to validate the page
141 (if appropiate) and raise any event based on the data you got in LoadPostData.
142
143 Q: How do I compare arrays with NUnit?
144
145 A: If the order of items in the array is predictable, Assert.AreEqual (array, array, string)
146    can be used.  Otherwise, you can use the following fragment in your code:
147
148    --- snip --- snip --- snip --- snip ---
149         private bool IsEqual(object[] a1, object[] a2, string assertion) {
150                 int     matches;
151                 bool[]  notfound;       
152
153                 if (a1.Length != a2.Length) {
154                         if (assertion != null) {
155                                 Assert.Fail(assertion + "( different length )");
156                         }
157                         return false;
158                 }
159
160                 matches = 0;
161                 notfound = new bool[a1.Length];
162
163                 for (int i = 0; i < a1.Length; i++) {
164                         for (int j = 0; j < a2.Length; j++) {
165                                 if (a1[i].Equals(a2[j])) {
166                                         matches++;
167                                         break;
168                                 }
169                         }
170                         if ((assertion != null) && (matches != i+1)) {
171                                 Assert.Fail(assertion + "( missing " + a1[i].ToString() + " )");
172                         }
173                 }
174
175                 return matches == a1.Length;
176         }
177    --- snip --- snip --- snip --- snip ---
178
179 Q: Why are controls inside my control not being rendered?
180
181 A: Your control probably has a [ParseChildren (false)], meaning that its
182 children will not be parsed as properties. In that case, the controls are added
183 to the Controls collection of your control. Text will be transformed into a
184 LiteralControl. When rendering, you'll have to check if you have any children
185 (Control.HasControls ()) and if so, either render the controls by yourself or
186 let the base class do it. If your control has no children, just render it as you
187 would normally do.
188
189 Q: My control has a public event. Do I have to do anything special?
190
191 A: Yes. System.Web.UI.Control has a 'Events' property that you have to use like
192 this:
193
194                 static object event_name_blah = new object ();
195                 ....
196                 public event EventType EventName {
197                         add { Events.AddHandler (event_name_blah, value); }
198                         remove { Events.RemoveHandler (event_name_blah, value); }
199                 }
200                 ....
201
202 If your control has a OnEventName that invokes EventName, you have to do:
203
204                 EventType deleg = (EventType) Events [event_name_blah];
205                 if (deleg != null)
206                         delege (arguments);
207
208 Why? Ben said that if you don't do this, every event, even if not
209 used, will take 4 bytes (on a 32 bit box), which is a total of 32 bits
210 (4*8). And there are lots of events there that are not always used.
211
212 Q: I hate all those casts when I use ViewState. How can I avoid those.
213
214 A:
215
216 Ben added nice helper methods:
217
218         internal bool GetBool (string key, bool def);
219         internal int GetInt (string key, int def);
220         internal string GetString (string key, string def);
221
222 If you have enumerations, you will have to cast them to integers to
223 take advantage of these methods. Casting also has the advantage of
224 using the integer view state form, which is more compact than the
225 enumeration one.
226
227 Q: ViewState does not seem to have all the values I expected. How do I get them?
228
229 A: By default, IsTrackingViewState property is set to false. That might be
230 preventing your control from storing some/all of the values. Use
231 TrackViewState() (protected) to enable that.
232
233 Q: How do I enable client side validation for validators?
234
235 A: a few things are required:
236    
237    1. In your machine.config, add the following line to your <httpHandlers>
238
239         <add verb="*" path="WebResource.axd" type="System.Web.Handlers.AssemblyResourceLoader, System.Web, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
240
241    2. Apply the patch file 'browscap.ini.diff' to your browscap.ini (this patch only
242       works if you're using firefox, IE6, or Safari.  I didn't bother with any others.):
243
244   Once these two steps are completed, just going to be a page with
245   validators that have EnableClientScript="true" (the default) should be enough.
246
247 Q: My control can get a URL in one of its attributes. The value can be something
248 like "~/blah" or "../bleh" or... How do I translate that into a URL that is
249 includes my application directory?
250
251 A: Use Control.ResolveUrl ().
252
253 Q: What should i do in AddParsedSubObject
254
255 A: For control like Label or Hyperlink where there is a text property,
256 you need to handle both plain text and child controls. See the code in
257 Label for a correct impl of this method