snarfblam
Leaders-
Posts
2156 -
Joined
-
Last visited
-
Days Won
2
Content Type
Profiles
Forums
Blogs
Events
Articles
Resources
Downloads
Gallery
Everything posted by snarfblam
-
What do you mean by a field? Is this a WinForms app or an Asp.Net app? Are you looking for some sort of input mechanism (i.e. text box)? Or are we talking about data storage?
-
Hate to be too critical, but why are you using the FileListBox? It is there for VB6 compatability. Although it may be more work and might seem like re-inventing the wheel, I personally would suggest that you use a regular list box (or better yet, a list view) and populate it yourself. That way, you have complete control over the display and function of the control.
-
There are two reasons that you could want to use a module. One is for backwards compatability with VB6, and the other is for a lack of a static class. A module is essentially the same as a static class. You can, however, create a class that is sealed with a private constructor to create the same exact effect as a static class. The big difference between the two is that there is an implicit project-wide import of a module (which is less object-oriented and more disorganized, which is why many prefer to not program with modules).
-
Keep in mind that the conversion was not only from VB to C# but also from 2003 to 2005. It is quite possible that the problem is a result of the different version of .Net. The behavior you describe to me doesn't seem all that surprising, considering that last line, but of course, I can't see the rest of the program. That last line, proc.WaitForExit(), will block the thread that started MAME until MAME closes. If that is the application's main thread or UI thread then it is very possible to introduce a race condition. As an example, your program's main thread is frozen, and it will stay that way until mame.exe closes, now suppose mame tries to obtain some information about the application that started it running, and in the process, MAME, Windows, or the .Net framework needs a function to be run on your main thread. Now your main thread is waiting for MAME, and MAME is waiting for your main thread, and no one gets anywhere. It shouldn't be an issue if MAME was executed from another thread, and even if it is run from the main thread that isn't necessarily exactly what your problem is, but I would say it is a possibility. Try running the code you posted from another thread (if you don't know much about threading, just check out the Thread class in MSDN).
-
Perhaps you are looking for this... Dtl_image.Image = Image.FromFile(SelFileName) You are calling the static method Imgae.FromFile from a reference to Dtl_image.Image, but doing nothing with the return result (such as storing it in Dtl_image.Image).
-
Off the top of my head, you can use the DllImport attribute or the Declare statement to access method from the DLL using VB.
-
Overriding Equals works, and IEquitable works. Predicates can work too. // Create a collection of objects for the example List<Control> controls = new List<Control>(); public void PrepareExample() { // Populate list controls.AddRange(new Button[] {new Button(), new Button()}); // Set one of the objects so that it will match our search criteria. controls[1].Name = "ThisIsTheButtonYouWant"; } public void PredicateExample() { // Create an object for the example that defines our search citeria. Control CompareAgainst = new Button(); CompareAgainst.Name = "ThisIsTheButtonYouWant"; // This is the important code Control ControlIFound = controls.Find( delegate(Control c) { return c.Name == CompareAgainst.Name; } ); MessageBox.Show(ControlIFound.Name); } That looks like a hefty chunk of code to determine whether a list has a certain object or not, but most of that code actually sets up the example. The heart of the code, which is the only code you will actually need to write in your program, is pretty short: Control ControlIFound = controls.Find( delegate(Control c) { return c.Name == CompareAgainst.Name; } ); More or less the same amount of code as would be written to override Equals or implement IEquitable. Like so: // We will have a variable we want to compare to, for example: Node checkAgainst; // Create a bool that indicates whether the list has an equal node. bool ItemIsInList = null != MyNodeList.Find( delegate(Node n) { return n == null ? false : n.nodeID = checkAgainst.nodeID; } }; Not recommending you fix your code that isn't broken, but it's always nice to have another way to do something, and Predicate<T> methods can do alot more than compare for equality.
-
I posted this class definition on another thread and decided that it would be a good idea to post it in the Code Library as well. It is a generic, global object caching class, working in a dictionary-like manner (and, in fact, backed by a Dictionary<string, TValue> object). Because of the way that .Net handles fields of static classes you are provided a complete and separate cache for each type. (Or, to be more accurate, for each type parameter. For example, you can store a Bitmap in Cache<Image> and it will not be found in Cache<Bitmap>. Likewise, a Bitmap stored in Cache<Bitmap> will not be found in Cache<Image>.) The Cache class provides indexers and enumerators, and is implemented in a manner that makes the use of keys to identify objects completely optional. static class Cache<T> { // Backing collection static Dictionary<string, T> values; static Cache() { // Create a dicationary with case-insensitive strings for keys. values = new Dictionary<string, T>(StringComparer.InvariantCultureIgnoreCase); } public static T GetItem(string key){ return values[key]; } #region Add/Remove methods /// <summary> /// Adds an object with a specified key to the cache. /// </summary> /// <param name="key">The key under which the object is stored.</param> /// <param name="value">The object to store.</param> public static void Add(string key, T value){ values.Add(key, value); } /// <summary> /// Adds an object to the cache, generating a key automatically. /// </summary> /// <param name="value">The value to store.</param> public static void Add(T value){ values.Add( //Create a key based on the object's hash code, ideally //ensuring that unique objects obtain unique keys. value.GetHashCode().ToString(), value); } /// <summary> /// Removes an object from the cache by specifying the key. /// </summary> /// <param name="key">The key of the object to remove from the cache.</param> /// <returns>A value indicating success or failure of the operation.</returns> public static bool Remove(string key) { return values.Remove(key); } /// <summary> /// Removes an object from the cache by specifying the key. /// </summary> /// <param name="value">The object to remove from the cache.</param> /// <returns>A value indicating success or failure of the operation.</returns> public static bool Remove(T value) { string key = null; foreach(KeyValuePair<string, T> item in values){ if(item.Value.Equals(value)) { key = item.Key; break; } } if(key == null) return false; return values.Remove(key); } /// <summary> /// Removes any items from the cache where the item meets the condition specified. /// </summary> /// <param name="condition">A delegate which processes an item and returns a boolean value /// indicative of whether or not the value meets a condition.</param> public static void Remove(Predicate<T> condition) { string[] keys = new string[values.Count]; values.Keys.CopyTo(keys, 0); foreach(string key in keys) { if(condition(values[key])) values.Remove(key); } } /// <summary> /// Removes any items from the cache where the key meets the condition specified. /// </summary> /// <param name="condition">A delegate which processes a key and returns a boolean value /// indicative of whether or not the value meets a condition.</param> public static void Remove(Predicate<string> condition) { string[] keys = new string[values.Count]; values.Keys.CopyTo(keys, 0); foreach(string key in keys) { if(condition(key)) values.Remove(key); } } /// <summary> /// Removes all items from the cache. /// </summary> public static void Clear() { values.Clear(); } #endregion #region Enumerators /// <summary> /// Gets an enumerable collection of all the objects stored in the cache. /// </summary> public static IEnumerable<T> Values { get { return values.Values; } } /// <summary> /// Gets an enumerable collection of all the keys that identify objects in the cache. /// </summary> public static IEnumerable<string> Keys { get { return values.Keys; } } #endregion } The Cache<T> class generally performs the same function that a statically declared Dictionary<TKey, TValue> object would, but it can be more convinient to write code with, and, again, the use of keys is optional. Unfortunately, because of a technical issue (overloading), Cache<string> will be difficult if not impossible to use. Here is an example of using the Cache<T> class. public void Example(){ // It could be handy to cache bitmaps that will be used application-wide. Cache<Image>.Add("OpenIcon", Image.FromFile(IconPath.OpenIcon)); Cache<Image>.Add("CloseIcon", Image.FromFile(IconPath.CloseIcon)); // Be careful--generics do not respect inheritance. // (They can't due to the way that .Net handles static members of generic classes.) // Throws exception because object is not cached in Cache<Bitmap>. Image OpenImage = Cache<Bitmap>["OpenIcon"]; // Works OpenImage = Cache<Image>["OpenIcon"]; // Cache is enumerable. // Let's display the contents of Cache<Image> using an image displaying form. foreach(string key in Cache<Image>.Keys) { // Create the form with the key for the caption and the associated image within the form. frmImageDisplay = new ImageDisplayForm(key, Cache<Image>[key]); // And show. frmImageDisplay.ShowDialog(); } }
-
What will have an effect on what intellisense shows is what the variable is declared as. If you store a Button in an Object variable, the compiler doesn't know that (and Button methods are not available without a cast) so intellisense will only show members of System.Object. If you declare the variable as Control you will see only Control-specific members.
-
Hmm... didn't put much though into the language, although I suppose I certainly should have. The rest of the thread is in VB. The reason I used C# is because I do most of my programming in C# and I already had that class written in C# (I just fancied it up for posting). If anyone wants it in VB, I'll gladly translate it.
-
To make your VB code pretty, use the tags, and to make C# code look pretty use [CS] tags. As for the difference between WithEvents and AddHandler, the only difference is that WithEvents does the wiring automatically. That means that if you declare a WithEvents variable, every time you assign an object to the variable, the handlers are automatically attatched and every time you remove an object from a variable (assign another object or assign Nothing to the variable) the handlers are removed. AddHandler/RemoveHandler gives you more control over how event handlers at attatched and removed, but if WithEvents suits your needs then that is probably your best bet because it requires a smaller amount of clearer code (but is harder to port to other languages). Both methods basically compile down to the same thing.
-
I don't know what particular option you might be losing in the translation, however there are a number of ways to enable visual styles in an application in VB.Net 2005. One way is the .Net 1.1 way, which is to have a sub Main that makes a call to Application.EnableVisualStyles as the very first statement. Another way is the .Net 1.0 way, which is to include a manifest with your application (an example of such a manifest is available in MSDN for .Net 1.x). A third way is through the "Application Framework," a feature in VB8 that creates a set of classes for you to manage your application with. Many people prefer not to use the Application Framework (there are plenty of reasons to not want to, for example, if you want to create your own Sub Main, if you don't want all the extra code and resources compiled in to use only one feature of the "Application Framework", or if you want your code to be more portable between languages), but if you don't mind using it go to your project settings, check "Enable Application Framework", and in the "Windows application framework properties" box check "Enable Xp Visual Styles".
-
Double-buffering. If you are using .Net 1.x you must implement this yourself, usually by doing all of your drawing to a Bitmap (this will be your backbuffer) and then when you are done drawing the bitmap to the screen. I often contain my graphics in a picturebox whose image is set to my back buffer. After I have drawn my image I invalidate the picturebox. (A good optimization is to invalidate only the region that has changed.) I recommend this method, simply because it is easy. .Net 2.0 has double-buffering functionality built in, but it is less flexible than using your own back buffer because you must use the standard painting mechanism for controls. This sort of double-buffering has to be implemented as follows: Set the DoubleBuffered property to true, or inherit from your desired control class and, in the constructor, use the SetStyles method to set DoubleBuffered and AllPaintingInWmPaint to true. Now your control is double-buffered. When using this method, as the AllPaintingInWmPaint style indicates, all drawing must be done in the Paint event or within the overridden OnPaint method. This means that when anything happens that effects what the graphical output should be, you must determine the region that is effected and pass that region to the Invalidate method of the control (or you can invalidate the entire control, but this will slow down the process). This is kind of a round-about way of doing things, but it is the Windows way. Calling Invalidate tells Windows that your control or part of the control needs to be redrawn, and then Windows tells your control that it needs to be re-drawn, which calls the OnPaint method and raises the Paint event, at which point you finally do your drawing. The logic of this second method tends to be more complex.
-
This is just my take on the situation, although there are probably others with more experience on the topic than I. I personally would recommend the latter option if you are serious about making the game look good. This involves much more work, though. Essentially, you must maintain a list of the visible objects on the screen that might interact with the mouse, and along with each object in the list you need a z-order value (z-order being an integer that specifies where, from top to bottom, an object is. An object that is drawn on top of a second object would have a higher [or lower?] z-order than that second object). Then, detecting which object the mouse is over can be done more than one way. The simpler would be to store a rectangle to represent the location of each card, and on a mouse click you can search through the rectangles, top to bottom (sorting rectangles by z-order) and find the first rectangle that contains the position where the mouse is. The more complex method would be for each object that can be represented on the screen to have a HitTest() method. HitTest() can examine the object's image and identify whether the pixel clicked is transparent or opaque. If it is opaque, return a true value, if transparent, return a false value. Call hit test on each object, from top to bottom (again, sorting by z-order) until you find an object that returns true for HitTest(). This latter method will be much more precise.
-
Well, here is a spiffed up version of the generic cache I was talking about: static class Cache<T> { // Backing collection static Dictionary<string, T> values; static Cache() { // Create a dicationary with case-insensitive strings for keys. values = new Dictionary<string, T>(StringComparer.InvariantCultureIgnoreCase); } public static T GetItem(string key){ return values[key]; } #region Add/Remove methods /// <summary> /// Adds an object with a specified key to the cache. /// </summary> /// <param name="key">The key under which the object is stored.</param> /// <param name="value">The object to store.</param> public static void Add(string key, T value){ values.Add(key, value); } /// <summary> /// Adds an object to the cache, generating a key automatically. /// </summary> /// <param name="value">The value to store.</param> public static void Add(T value){ values.Add( //Create a key based on the object's hash code, ideally //ensuring that unique objects obtain unique keys. value.GetHashCode().ToString(), value); } /// <summary> /// Removes an object from the cache by specifying the key. /// </summary> /// <param name="key">The key of the object to remove from the cache.</param> /// <returns>A value indicating success or failure of the operation.</returns> public static bool Remove(string key) { return values.Remove(key); } /// <summary> /// Removes an object from the cache by specifying the key. /// </summary> /// <param name="value">The object to remove from the cache.</param> /// <returns>A value indicating success or failure of the operation.</returns> public static bool Remove(T value) { string key = null; foreach(KeyValuePair<string, T> item in values){ if(item.Value.Equals(value)) { key = item.Key; break; } } if(key == null) return false; return values.Remove(key); } /// <summary> /// Removes any items from the cache where the item meets the condition specified. /// </summary> /// <param name="condition">A delegate which processes an item and returns a boolean value /// indicative of whether or not the value meets a condition.</param> public static void Remove(Predicate<T> condition) { string[] keys = new string[values.Count]; values.Keys.CopyTo(keys, 0); foreach(string key in keys) { if(condition(values[key])) values.Remove(key); } } /// <summary> /// Removes any items from the cache where the key meets the condition specified. /// </summary> /// <param name="condition">A delegate which processes a key and returns a boolean value /// indicative of whether or not the value meets a condition.</param> public static void Remove(Predicate<string> condition) { string[] keys = new string[values.Count]; values.Keys.CopyTo(keys, 0); foreach(string key in keys) { if(condition(key)) values.Remove(key); } } /// <summary> /// Removes all items from the cache. /// </summary> public static void Clear() { values.Clear(); } #endregion #region Enumerators /// <summary> /// Gets an enumerable collection of all the objects stored in the cache. /// </summary> public static IEnumerable<T> Values { get { return values.Values; } } /// <summary> /// Gets an enumerable collection of all the keys that identify objects in the cache. /// </summary> public static IEnumerable<string> Keys { get { return values.Keys; } } #endregion } Very simple to use. You automatically get a separate cache for each class type, and the use of keys is strictly optional. Duplicate keys are not allowed. public void Demonstrate() { Cache<int>.Add("five", 5); Cache<int>.Add("six", 6); // Shows "5" (the key "FIVE" is the same as "five" because the cache uses case-insensitive keys) MessageBox.Show(Cache<int>.GetItem("FIVE").ToString()); // Throws exception, there is no object stored under the key "six" // in the Cache<double> collection. MessageBox.Show(Cache<double>.GetItem("six").ToString()); // Shows "5", then "6" foreach(int value in Cache<int>.Values) { MessageBox.Show(value.ToString()); } } Of course, all the Cache<T> class really does is wrap and globalize the Dictionary class, but it makes project-wide caching much, much easier. Insert the code into your project, and then you don't need to declare any collections or maintain references to them. Of course, a more elaborate global collection class could be written to create the namespace-like scheme that Blitz3D appearently uses, but I personally don't have much use for such a class.
-
Yes, it is DropDownList. The only problem with using the DropDownList style is that you can not set the SelectedIndex property at runtime, which means that you must write code to do so or always start with a blank combo box.
-
Have you tried multithreading? Or at least a call to Application.DoEvents() when you want to update? By the way, I don't know if this can be done with a batch file, but instead of starting your process and then later finding it by name, can't you just hold on to the Process object returned by Process.Start?
-
Don't know what it is that you found on the net, but for caching objects I've found that a static generic class that maintains a simple list or dictionary of objects is very convinient. The best part is that because static generic classes create a set of all the static variables for each generic parameter, you automatically get a separate cache for each type of object, and with a very small amount of code.
-
C++ offers a special kind of type that is not present in C#: a union. For anyone who is not familiar with unions, here is a quick explanation of how they work and what they're good for. How They Work A union is somewhat like a struct. A union definition defines a type. A union type has fields and methods like a struct. The key difference is that a union stores all of its fields in the same memory location, whereas a struct stores each field in a different memory location. http://ilab.ahemm.org/imgHost/nonunion.gifhttp://ilab.ahemm.org/imgHost/union.gif What they are good for The primary use for a union is to conserve memory. Because the fields are stored in the same memory, generally only one field can be used at a time. Assigning one field changes the values of all fields, possibly to an invalid value. But, because all fields are stored in the same location, the size of the union is the size of the largest field, whereas the size of a struct is, at least, the total of the sizes of all fields. There is another use for unions too: treating the same binary data as different kinds of values. For instance, we could store an IntPtr in a union and then retrieve the value as a regular Int32. In other words, we can convert and dissect data with a union. Why Bother? Nearly any kind of conversion we could make through the use of a union we could make through the use of the Convert and BitConverter classes, so why bother using a union? Because it would be fast. The use of a union would be as an optimization. Although a union can occasionally produce less code than the use of conversion classes, the code tends to be harder to read and must be written with much more care because it can introduce kinds of bugs we aren't used to encountering. They should only be used when you really need the speed. And Now, For Your Viewing Pleasure If unions are a feature that is not present in C# then why did you read all that? Because unions are a feature present in the Common Language Runtime, and this feature can be utilized through the use of attributes, specifically the System.Runtime.InteropServices.StructLayoutAttribute and the System.Runtime.InteropServices.FieldOffsetAttribute. Where C++ uses the union keyword for unions, C# must modify a struct with attributes to produce the same behavior. System.Runtime.InteropServices.StructLayoutAttribute allows us to specify how, in memory, the fields of a struct will be laid out : automatically, sequentially, or explicitly. We are looking for the last of the three. When we are using an explicit layout, System.Runtime.InteropServices.FieldOffsetAttribute is the attribute that specifies where in memory the field will be. For instance, to view the binary value of a char as an unsigned integer, we could use the following struct: [structLayout(LayoutKind.Explicit)] public struct CharShortConverter { [FieldOffset(0)] public char Char; [FieldOffset(0)] public ushort UShort; // This method is not necessary to use a union, but it is very helpful because // otherwise we would have to explicitly initialize all the fields each time // we declare a variable of this type. public static CharShortConverter GetConverter() { CharShortConverter converter; converter.Char = ' '; converter.UShort = 0; return converter; } } This struct could be used as follows: // Get a converter CharShortConverter converter = CharShortConverter.GetConverter(); // Assign a char to the union, read it back as a UShort, and display the value. converter.Char = 'x'; MessageBox.Show(converter.UShort.ToString()); It would be much quicker, of course, to write code that used the BitConverter class, and usually much smarter, too. If, however, we had to convert a very large number of chars to ushorts, the use of a union could speed things up quite a bit. Instead of invoking a function we only need to assign a variable and read it back. Shortcomings The first shortcoming of this method is clearly visible in the first code listing. Because C# has no understanding of what a union is, it does not understand that assigning a value to one field initializes all fields, and so we must initialize the same memory multiple times to make the compiler happy. To make our lives easier, it is smartest to write a static method that will return an already-initialized variable. The second shortcoming is that, unlike C++, a C# union can't contain arrays. C# unions can't contain any reference types (reference types are garbage collected and structs are not), and arrays are reference types. This means that where in C++ we could access the bytes of an 64-bit integer by index, in C# we must declare eight fields and access them by name. A Useful Example The CharShortConverter isn't particularly useful, although I have a much more useful example, which is actually the reason I investigated unions in C# in the first place: image processing. When using unsafe code or the Marshal class to access raw image (as in the tutorial, Bitmap Manipulation) data it is very handy to have a quick way to access the individual color components of each pixel, and so we have the Pixel struct. // Represents a 32-bit ARGB pixel // Allows pixel data to be accessed much faster than via // the Color struct or the BitConverter class. [structLayout(LayoutKind.Explicit)] public struct Pixel { // Composite ARGB value [FieldOffset(0)] public int ARGB; // Color components [FieldOffset(3)] public byte A; [FieldOffset(2)] public byte R; [FieldOffset(1)] public byte G; [FieldOffset(0)] public byte B; // Method to get an instance of this union public static Pixel GetPixel() { Pixel result; result.A = 0; result.R = 0; result.G = 0; result.B = 0; result.ARGB = 0; return result; } // Set this union to represent the specified color public void LoadColor(System.Drawing.Color c) { ARGB = c.ToArgb(); } // Create a Color struct that represents this union public Color ToColor() { return Color.FromArgb(ARGB); } }
-
- 1
-
Set the Hinting (might be TextHinting or something like that) property of the graphics object. There should be an option for anti-aliasing, an option for clear-type, and an option for aliased. That should help with the quality.
-
Cags, we are looking at combo boxes, not check boxes, and we want to set them all to their first value, not the first one to a specific value. shankar, I don't think that you want to test whether the item count is one, since that won't work on any combos that have more than one item. Maybe something along the lines of foreach (Control ctrl in ctrls.Controls) { ComboBox combo = ctrl as ComboBox; // Save type checking and code by using 'as' operator if(combo != null && cb.Items.Count > 0) { // Count should be > 0 combo.SelectedIndex = 0; } } By the way, the [CS] tags are very handy.
-
An overridden method can be sealed and an inherited field can be made private and protected with an accessor property. When dealing with events the only way to give the base class the ability to control an inheritor's use of an event is by disallowing the inheritor from directly invoking the event, leaving it up to the base class to explicitly provide a means of raising an event should it be necessary. That might not necessarily be Microsoft's reason, however. There is also a technical limitation. At the MSIL level, an event is actually composed of four parts: A private field whose type is a multi-cast delegate, for example System.EventHandler--this is where all the attatched event handlers are stored A method to add a delegate to the private field A method to remove a delegate from the private field A piece of MSIL metadata that declares an event by providing a name, a method through which a delegate can be attatched (#2), and a method through which a delegate can be removed (#3). Note that because the backing field (#1) is private, only the declaring class has access to it, not inheriting classes, therefore only the declaring class can invoke it. Now, Microsoft could add a protected, read-only property that allows inheriting classes to obtain and invoke the underlying delegate, but why go out of your way to permit programming practices that break the OOP paradigm?
-
The reason you see this behavior in .Net 2.0 is because in .Net 2.0 we generally use the ToolStrip control, the control with this problem. In .Net 1.x we used the ToolBar control, which still does not have this problem in 2.0. I hoped that in this situation perhaps the MouseDown event could be handled, where a hit test could be performed to see which button was clicked so that we could, by calling the PerformClick method of a ToolStripItem, force the click through code. The problem, it seems, is that the ToolStrip does not recieve MouseDown or Click events when the form it's on does not have focus.
-
To answer your first question (the use of the = operator): Of course, X will not = 20. You need to understand how assignment works with value types and reference types--the behavior of = is, in fact, already explicitly defined. If you look at it from the right prespective, they actually work the same way. First, examine the way that normal (value-type) variable assignment works. When you say SomeVariable = SomeValue, you have a spot in memory referenced by SomeVariable and the value, SomeValue, is copied into that spot in memory. Let's look at a play-by-play: '--------------------------X----Y dim x as integer = 5 ' [u]5[/u] 0 The value of 5 is copied to x dim y as integer = 10 ' 5 [u]10[/u] The value of 10 is copied to y x = y ' [u]10[/u] 10 The value of Y (10) is copied to x y = 20 ' 10 [u]20[/u] The value is 20 is copied to Y (but not to X) Now we look at reference types. If you have any experience at all with C# or ASM, you will be familiar with pointers. A pointer is just a 32-bit integer (in Win32) that references a memory location. Pointers are at the heart of .Net reference types. A variable that is declared as a reference type actually only stores a pointer. When you call a method or set a field or property, you tell the compiler "Perform this operation on the object stored at the memory location specified by my variable." For example, the code MyObject.SomeFunction() compiles down to "Call SomeFunction on the object that the pointer in MyObject points to." The signifigance of that is that you must understand that reference-type variables are just pointers, internally represented exactly like an integer. So, when you assign an object to a variable, the reference (i.e. the pointer) is being assigned. Let's have a look. 'Class that holds a single value Class SampleClass Public Value As Integer 'Create instance with specified value Public Sub New(val As Integer) Value = val End Sub End Class 'Now, let's examine how assignment works here. 'These memory locations are random, picked out of a hat, just to demonstrate. Sub ShowAssignment() 'MemoryLocation----------------X----------------Y--------------------- 'Value-----------------------------------X--------------Y------------- Dim X As New SampleClass(5) '[u]123456[/u] [u]5[/u] 0 (Nothing) Dim Y As New SampleClass(10) '123456 5 [u]90210[/u] [u]10[/u] X.Value = Y.Value '123456 [u]10[/u] 90210 10 Y.Value = 20 '123456 10 90210 [u]20[/u] ' So far the values seem to be exactly the same as before. ' Here's where things get different: ' We will assign the pointer of Y to X X = Y '[u]90210 20[/u] 90210 20 ' X now points to a different location in memory than before: the ' same location as Y. Now a change in Y will be reflected in X, and ' vice-versa X.Value = 100 '90210 [u]100[/u] 90210 [u]100[/u] ' Notice that because X and Y point to the same memory, their value ' WILL ALWAYS be the same. End Sub The confusion comes from the fact that .Net does a real good job of hiding your pointers from you. If you get a good grasp on how pointers work, though, you will have a good understanding of how and why reference types behave the way they do. To answer your question about making an exact copy of a button: This is not nearly as simple as it seems. If you create a member-by-member clone ("shallow copy") of a button you will run into problems, and fast. Button objects are full of pointers. If you create a member-by-member clone of a .Net Button object you will copy all the pointers instead of the data that the pointers reference (copying all the data that the pointers point to would be a "deep copy"). This means that you will have two objects that .Net thinks are separate buttons, but they will both reference the same Windows resources (i.e. Windows will think that they are the same button while .Net thinks they are different). If you assign one Button variable to another it will just copy .Net's pointer, so both .Net and Windows will treat it as the same object. If you want to create a duplicate of a Button you will have to write your own function to do so. It will have to create a new button and then copy all of the properties over.