|
Dear All,
I want to know, is there any inconvenients / mistakes will occur if I use an ArrayList to store up some classes dynamically? The class contains quite a lot of infos.
In my application, I need to create a class array e.g: ImageInfo[] imgInf, however, I the size maybe change at anytime.
For example, inside Init function, I will create an array as :
ImageInfo[] imgInf = new ImageInfo[1];
The size of array should be at least one, and its size will increase / decrease when I add/delete infos.
I don't know, how can I dynamically insert/remove a new array to imgInf, so I decided to use ArrayList to store the class,; e.g. use ArrayList.Add();
but I'm worried about it will cause some mistakes..
Could anyone give me some idea?? Thank you
|
|
|
|
|
ArrayList is a good choice when the array will be changing size. If you used an actual array (whatever[]), you would need to write your own code to re-allocate the new block and copy the old stuff to the new array, making sure to insert and delete appropriately. Writing your own code when other code already exists to do the job is generally a mistake, since you'll create new bugs and spend time that didn't need to be spent.
In short, the only mistake you would need to worry about with ArrayList is if you put something in it that is not of the type that you want to be storing there. (Casting is required in order to use the object when you pull it out.)
John
"You said a whole sentence with no words in it, and I understood you!" -- my wife as she cries about slowly becoming a geek.
|
|
|
|
|
You could also always extend CollectionBase (or make your own, which would implement IList which implements ICollection and IEnumerable ) and make strongly-typed params for the type you want. The CollectionBase (and many other collections, for that matter) use a backing ArrayList to store objects, but by having typed parameters you avoid putting objects of different Types in the list because the compiler would fail if you tried adding something else. Extending CollectionBase isn't hard (see the documentation in the .NET Framework SDK for information on which methods have to be overridden and an example) and ensures that you won't add an instance of a different Type to the list.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Currently I am doing a vector drawing program which user need to input text using true type font.
Previously in C++ I am doing the conversion by myself.
But I heard that .Net can do the conversion automatically for me, is that true?
Thanks a lot
songling
|
|
|
|
|
I'm not sure where you heard that, but it was probably in reference to XAML using the Avalon UI layer for Windows code name "Longhorn" to be shipped in 2007 (if they don't let the date slip again). It is 90% compatible with SVG and uses the same concepts.
The Font class as it is in .NET now is just a wrapper for all the font APIs in Win32. In fact, many of the classes (especially Windows Forms controls) just encapsulate native functionality (for Windows Forms controls, they encapsulate the corresponding common controls). All the drawing stuff is actually just wrapping GDI+ so all the native functionality provided by GDI+ is about all you get out of .NET. Now, if you were to use the Metafile class (derives from Image ) and use a Graphics object to draw a Font (while recording), then it at least records the strokes. I'm not sure how this is in relation to vector-based fonts, but the EMF that is produced is a vector image. You could always give it a try.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
I can apply an XSLT to an XML document fine in C#.
But an issue occures if the XSLT has a for-each.
For some reason the xmldom seems to ignore it. I have read posts from other people with this problem but no solution, any ideas? (Can some kind person try to reproduce this bug)
Heres the code I use for the transform:
StringWriter sw = new StringWriter();
XmlDocument srcDoc = new XmlDocument();
srcDoc.Load("test.xml");
XslTransform srcXSLT = new XslTransform();
srcXSLT.Load("test.xslt");
srcXSLT.Transform(srcDoc, null, sw);
Output.Text = sw.ToString();
XML Doc:
(Sorry, I made the greater thens less thens and vice versa by accident in this post )
>?xml-stylesheet type="text/xsl" href="sample.xsl"?<
>catalog<
>book id="bk104"<
>author<Corets, Eva>/author<
>title<Oberon's Legacy>/title<
>genre<Fantasy>/genre<
>price<5.95>/price<
>publish_date<2001-03-10>/publish_date<
>description<In post-apocalypse England, the mysterious>/description<
>/book<
>book id="bk106"<
>author<Randall, Cynthia>/author<
>title<Lover Birds>/title<
>genre<Romance>/genre<
>price<4.95>/price<
>publish_date<2000-09-02>/publish_date<
>description<When Carla meets Paul at an ornithology>/description<
>/book<
>/catalog<
XSL Doc:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr><td><b>Author</b></td><td><b>Title</b></td></tr>
<xsl:for-each select="//book">
<tr>
<td><xsl:value-of select="author"/></td>
<td><xsl:value-of select="title"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Here is the output I get:
<html>
<body>
<table border="1">
<tr>
<td>
<b>Author</b>
</td>
<td>
<b>Title</b>
</td>
</tr>
</table>
</body>
</html>
Matthew Hazlett
Windows 2000/2003 MCSE
Never got an MCSD, go figure...
|
|
|
|
|
Found out this is a documented bug in .NET
I had to resort to using the old COM objects..
Matthew Hazlett
Windows 2000/2003 MCSE
Never got an MCSD, go figure...
|
|
|
|
|
If I were you, don't use the xsl:for-each , use xsl:apply-templates instead. This does work great and gives you greater control over multiple views (using the mode attribute). Besides, if you're doing this in a .NET application/library, interoping with COM just to get your XSLt to work is too expensive, IMO, because all the calls must be marshalled.
Also, don't use //book since you're already at the root of the document (not the root element) - it causes the XPath parser to prepare for deep traversal and isn't as effecient as, say, using catalog/book or /catalog/book. As an example using xsl:apply-templates , see the example:
<xsl:stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/"> <!-- Also serves as a catch-all so you don't
have stray elements being output -->
<html>
<body>
<table border="1">
<tr><td><b>Author</b></td><td><b>Title</b></td></tr>
<xsl:apply-templates select="catalog/book"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="book">
<tr>
<td><xsl:value-of select="author"/></td>
<td><xsl:value-of select="title"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Is there any way to for each through an enum ?
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|
Got it, thanks.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|
Hiya. I'm using Visual C# - does anyone know how to declare a variable in say FrmMain - int myVar = 6; and then in a child of FrmTempTools set myVar to a value so i can read it again in my main form?
I have tried and can only get meesages such as undeclared variable in FrmTempTools.
Thanks anyone,
surgeproof.
|
|
|
|
|
Make the variable as public, or create a public getter property for the variable. Then just pass the Form instance to your FrmTempTools child.
public class FrmMain : Form
{
public int myVar = 6;
public FrmMain()
{
ChangeTheValue();
}
private void ChangeTheValue()
{
ChildOfFrmTempTools t = new ChildOfFrmTempTools(this);
Console.WriteLine(myVar);
}
}
public class ChildOfFrmTempTools
{
public ChildOfFrmTempTools(FrmMain mainInstance)
{
mainInstance.myVar = 12;
}
}
Also note you can use the ref or out keywords to pass the variable by reference, rather than the default of passing by value. For instance
public void Test()
{
int i = 6;
Modify(ref i);
Console.WriteLine(i);
}
public void Modify(ref int i)
{
i = 12;
}
---------------------------
He who knows that enough is enough will always have enough.
-Lao Tsu
|
|
|
|
|
thanks. i think i get it now!
surgeproof.
|
|
|
|
|
On trying to follow through and adapt your code, i only get this error: No overload for method 'bladeblahFormName' takes '1' arguments. Any ideas?
thanks.
|
|
|
|
|
i'm building a plugin-based application and have just migrated to loading them in separate appdomains for nifty unloading etc.
one problem though,
when the plugin is launched in a separate appdomain, ProcessDialogKey is not called in the forms that some of the plugins have. As soon as I load them in the default AppDomain, it works flawlessly.
i use .net 1.1.
Anyone?
|
|
|
|
|
AppDomain s separate the code completely. The only way to talk to each other is through Remoting (or some custom socket communication or something). Loading plugins into a separate AppDomain is not a good idea for this reason - they can't communicate with the application except through Remoting, which decreases performance since calls have to be marshaled across application boundaries.
There are many articles here on CodeProject about designing effective plugin type applications. You don't have to unload the assembly to unload your plugin. You simply need a way to dispose of the plugin, such as setting all instances to null or disposing it through the IDisposable implementation (you don't have to implement it, but it's a good idea) and clean-up the resource. In your app, just check if the plugin is disposed before using it. If you want to nullify its instances, just check for that.
If you must load these into separate AppDomain s, then consider that each AppDomain cannot talk to each other except through Remoting (which means that keys processed in a plugin cannot be handled by the main application since they're in different threads). You'll have to devise some way to tell the host application that keys were pressed, perhaps by using a binary formatter through a TcpChannel and firing some event that the host application can handle (again, through Remoting). This is a kludge, though.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Heath Stewart wrote:
You don't have to unload the assembly to unload your plugin.
AFAIK, assemblies can't be unloaded anyway (unlike AppDomains).
|
|
|
|
|
Gee, really? I guess working with .NET since 1.0 beta 1, architecting large-scale enterprise managed applications, and being an MVP didn't teach me that. (BTW, that's annoyed sarcasm)
I didn't say he could unload the assembly, only that he could unload (i.e., nullify or dispose the instance) the plugin. Unloading the assembly is often moot on modern machines.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
the only way to unload an assembly is to load it in a separate AppDomain, that i have read in many places.
but you made me think - is the reason the ProcessDialogKey is not called in the form in the plugin that it's sent only to the default AppDomain? then how do i catch it? the plugin is the only showing form in the program.
|
|
|
|
|
I didn't say that you can unload an assembly, I said that you can "unload" your plugin (by nullifying or disposing the instance of the plugin class). This is the common approach. See my sig - trust me, I know.
In order to work with the UI, messages must be sent to the control in the same thread that the control was created in. Since AppDomain are separate from each other, these threads are not accessible from another AppDomain . As I said before, process the input from the plugins and fire an event that can be remoted across application boundaries that your main application can handle. It's a lot of extra work for something so trivial, though. Honestly, does your app have so many plugins (which could all be in one assembly anyway, if needs be) that you must unload the assembly in which the plugin is contained?
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
first, i must say thanks a lot for the help, really appreciate it.
but the .dll file will still take up memory unless you unload the domain, doesn't it?
but i don't really understand what you mean about the UI.
everything in the form (created from the plugin in the separate AppDomain) work like a charm, EXCEPT ProcessDialogKey. you say "process the input from the plugins and fire an event that can be remoted across application boundaries that your main application can handle", but it is the plugins that want the event. the plugin have created the form, but the ProcessDialogKey is just not called when i press the TAB key etc.
really sorry if i misunderstood you.
|
|
|
|
|
zilch wrote:
but the .dll file will still take up memory unless you unload the domain, doesn't it?
Yes, but not very much depending on the size of the assembly (and how much IL has been JIT'd). On modern machines, this is very moot unless you plan on having 100s of plugins or something. Our flagship enterprise app uses dozens of rich plugins and - while everything is disposed properly - doesn't use much memory (as far as managed applications go). The majority of memory is used for instances of your classes, not the assembly or the JIT'd native instructions that are cached. If you ship several plugins for your application, consider grouping these classes together. The .NET Framework Class Library (FCL) doesn't have one class per assembly, does it? Having to unload the assemblies once the plugins that contain it is not necessary except in rare cases when memory is a problem (like on Windows CE platforms).
So you're saying the plugins are not getting ProcessDialogKey called in the forms that the plugins create? Are these modal or modeless dialogs? Are these dialogs created in separate threads? The forms are actually classes in the plugin assembly (loaded into a different AppDomain )? I'm just trying to understand what exactly is doing what.
Seriously, though, consider dropping separate AppDomain s. Communicating within the same AppDomain is so much easier if you need your plugins to talk to either other or to the main application. The assemblies for plugins aren't loaded until the Type that needs to be loaded and executed (from that assembly) is needed anyway. Depending on how your application loads plugins (like ours works like the COM registry to enumerate plugins from the .config file but doesn't create them until they're needed), many of them might not get loaded anyway.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
i get your point with the memory, i'll think more about it.
but the real issue here is the ProcessDialogKey. Yes the plugins create the forms themselves. From the contextmenu on the NotifyIcon i press the name of the plugin. The hidden GUI responds to this and calls Execute() on the plugin in the other AppDomain. From here they create their own forms. They are modeless (Show). I tried making them modal now (ShowDialog) and strangely ProcessDialogKey did get called! However (!) this messes things up as other plugin forms already showing can't get focus if i don't close the modal one first (i only tried making one plugin modal, and i need many plugins showing at the same time). I don't create any threads anywhere (except before the call to Application.Run()).
I am considering dropping them now, but only then becuase of ProcessDialogKey. I have already made the whole infrastructure adapted for remoting. And yes you are right, its much easier with one AppDomain.
thanks again, very kind of you to help me.
|
|
|
|
|
i changed form.Show() in the plugin to Application.Run( form ) and now it works. That, I call magic. why does it work now? i don't see the connection, but then again win32 message loops are not my strong side
|
|
|
|
|
Did you ever resolve this? We have a plugin system that really needs to be in a separate AppDomain, but when we place the plugin (which is a form) in its own AppDomain, ProcessDialogKey is never being called.
Thanks!
-Greg
|
|
|
|
|