| Profilo di StephenBadCorporateLogoFotoBlogElenchi | Guida |
|
10 giugno Making a Designer of Your Own - House SaladLast time, I started to write about the managed designer infrastructure in Visual Studio. This infrastructure is all part of the .NET Framework's System.ComponentModel namespace, and so it naturally deals with components (things that implement System.ComponentModel.IComponent) as the base unit. The component model is meant to provide a generic framework for any kind of designer, but in Visual Studio it was implemented specifically to support Windows Forms and source code generation. It was later made more generic, with the intention of supporting any components, but there is still a lot of implementation that works only with Controls. So what does the Control designer have to do with making a designer for XNA Framework game components? Nothing, except that in order to re-use the existing infrastructure, you'll need to know a bit about Control designers. Combining all the ingredients available in the Component Model to create a visual programming experience for XNA game components takes a fair bit of background knowledge. As I said in my last post, you can't just look at my recipe for a Game State designer and know how to build your own Input designer. The bulk of the implementation isn't in my code - it's in the designer infrastructure. If you want to make your own dishes, you need to know what's in the pantry, and how to combine certain things to get the desired flavor. Last time, I showed how any class deriving from Component will support a design view in Visual Studio. This design view is based on the concept of composition. You add objects to the class by dragging them from the Toolbox onto the design surface. Doing so results in a field being declared for the new object instance, and code to instantiate and initialize it. The designer lets you select and name objects on the design surface so that you can further edit them in the Properties Window. After making these changes, the entire design surface is serialized to code so that the composite class can be compiled and then re-created at runtime. When you design a Control, the objects on the design surface are usually represented at design time by the same objects you'll use at runtime. So when you add a Button to the Form designer, a real Button instance is created on the design surface to represent the Button instance you'll get at runtime. When you change the Text property on the Button in the Properties Window, the text on the button changes on the design surface because you've actually changed the Text property of that Button instance. You can change the BackColor and ForeColor properties for more visual evidence that the Properties Window is letting you edit the actual control instance on the design surface. At first glance, you might imagine that the Properties Window is using reflection to enumerate the properties of the selected object, get their values, and allow you to set them. That makes sense and might even seem pretty obvious at first... But if you change the Visible property to false, suddenly things are not so obvious. The button is still visible on the design surface! (If you aren't sure what Visible is intended to do, you can run the project at this point to see that the button isn't visible at runtime.) Figure 1 - Something invisible is revealed when you set the Visible property to false. The reason the Button didn't disappear is because the Visible property in the Properties Window doesn't belong to the Button the way the Text, BackColor, and ForeColor properties do. Instead, it belongs to the Button's designer. :-) At this point, things are undoubtedly going to get confusing. The term "designer" is overloaded, and I need to use it to mean something other than the visually-oriented composition editor we've been discussing until now. Every component created on the design surface has a designer associated with it. The designer is another class that modifies the design-time appearance and behavior of the component. One role of the component designer is to filter or enhance an object's metadata. To put it another way, it can change the attributes on a component or its properties, and can remove, replace, or add properties. A designer can do this to change both the appearance and behavior of a control at design-time. As an example, the Button's designer replaces the Visible property with a different property that comes from the designer instance. In designer-speak, this is called shadowing. In the Properties Window, the Visible property appears to belong to the Button, but in fact it belongs to the Button's designer. When you change the Visible property value, it's the designer's property that is changed (you don't see the effect because the designer was never visible in the first place). This prevents the Button instance from becoming invisible, which would make it hard to select or reposition it on the design surface. If you look more closely at the properties of the Button instance, you'll notice there are a few listed that aren't actually properties of the Button class. To pick out just a few, in the Design category, you'll find "GenerateMember", "Locked", and "Modifiers". These control whether the instance will be declared as a field of the class or a local variable, whether the control can be moved or resized on the design surface, and the visibility modifier of the field declaration (if there is one), respectively. Changing these properties affects the code generated for the Button instance, but they don't represent actual properties of any object on the design surface. A basic designer implementation is provided by System.ComponentModel.Design.ComponentDesigner. This class makes it easy to override just the parts you want to modify. As the documentation says, you associate a designer with a component through the DesignerAttribute. Now, a word of caution when using the DesignerAttribute. Its constructor has overloads to use System.Type or System.String arguments to specify the designer's type. If you implement the designer in the same assembly as the component, you can use the System.Type constructor. However, if you implement the designer in a separate assembly, it is almost always a good idea to use the System.String constructor. The reason is that the designer is always given a reference to the component instance, and if you want the designer to be able to reference that component by its proper type, it will be dependent on the component's assembly. That precludes having a reference to the designer assembly from the component assembly, because then you have a circular dependency. So the way to avoid it is to allow you component to be ignorant of its designer, except for its name. A very good reason to have the designer in a different assembly is because the designer will often depend on a bunch of assemblies that you don't ever need at runtime, or that maybe aren't redistributable. In fact, the designer class itself is not needed at runtime! So if you keep it in a separate assembly, then you can keep your runtime libraries lightweight and your redist small. Your customers will appreciate that! I think I'll wrap it up here. Next time, I'll write more about how designers affect the behavior of controls on the design surface. At this point, it's also appropriate to start using code samples to illustrate, and I don't have anything ready right now. RiferimentiL'URL di riferimento per questo intervento è: http://badcorporatelogo.spaces.live.com/blog/cns!43EB71B104A2D711!286.trak Blog che fanno riferimento a questo intervento
|
|
|