Is it possible in WPF to provide an alternate class which should be used as the control to show in the designer instead of the control itself, just like DesignerAttribute does for WinForms?
EDIT:
What I'm looking for is what happens with e.g. the ReportViewer class does. This class has an associated class ReportViewerDesigner which is used in the designer instead of the ReportView class itself.
You can manipulate the Metadata Store; since WPF separates the designer metadata into a separate assembly as noted in the MSDN.
In the System.ComponentModel
framework, a designer type is
associated with its corresponding
component through the
DesignerAttribute metadata attribute.
This means the relationship is
established at compile time, forcing a
hard-coded dependency between the
component's run-time and design-time
behavior. To attach a different
designer, you must change the
DesignerAttribute declaration and
recompile the component's code base.
In the WPF Designer, designer metadata
is factored into a separate assembly,
physically decoupling it from the
run-time implementation. This freedom
means that different tools can present
completely different design
experiences for the same run-time
type. For more information, see
Metadata Store.
A concrete example of this is the VS designer versus the Expression Blend designer.
EDIT:
As noted in the comments section they are fundamentally different approaches. It is not a 1:1 by any means; just as is with a WinForms versus WPF approach to building an application. If you are looking for an elusive attribute which will simply use a differing class as the designer representation; it does not exist. There are certainly ways to achieve what you want and allow the designer to display a given control in a myriad of ways but the approach is not like that of WinForms.
How To: Use the Metadata Store
WPF Designer Extensibility
Architecture (look at Designer Instance Creation)
Related
For WPF/Silverlight/XAML4Win8/WP8/whathaveyou, the visuals are created by (I believe) newing up an instance of the base class that your custom view (window/page/usercontrol/whathaveyou) is derived from, and then applying your XAML after the fact.
If I'm not mistaken this means codebehind in the type's constructor is lost. Is there a way to execute design-time object creation logic in the view itself? More importantly is there a good summary online somewhere of how the Cider/Blend designers actually create the WYSIWYG views at design time? I seem to recall some documentation on this somewhere (Expression Studio docs maybe?) But I can't find them for the life of me.
http://msdn.microsoft.com/en-us/library/ff602274(v=vs.95).aspx
The above link applies to Silverlight, but pretty sure most if not all applies to WPF as well.
You can instantiate a designer DataContext.
<Grid x:Name="LayoutRoot" Background="White"
d:DataContext="{d:DesignInstance Type=local:Customer}">
One limitation is that it requires you to have a default constructor. Here is an answer I found to get around it.
How to use d:DesignInstance with types that don't have default constructor?.
Best would be to subclass the data you are coding against and have it do any necessary initializing. Luckily everything you are defining is purely for the designing and has no effect on what objects you are actually working with at runtime.
Unfortunately I do not have answers for the rest of the questions.
what kind of stuff do you need to do in the constructor?
Could you do it by adding either dependency or attached properties with DependencyPropertyChanged hooks and setting values in the xaml?
Then you’d still get your code executing, but not the constructor?
Not sure the exact terms to use here, so any help would be appreciated.
To be the most simplistic, I have a forms application. When I load "form.exe", the form has one control, a menu. This menu has one menuitem, "Exit". What I would like, is when the Form is loading, be able to pass in arguments to this forms app that specify DLLs that could add specialized methods, controls, etc.
Now when I load "form.exe add_plugable.dll", my menu has another menuitem, "Add".
When I load "form.exe add_plugable.dll remove_pluggable.dll", menu has 3 items "Exit", "Add", and "Remove".
Hope this makes sense. What do I need to include in the Forms application and how do I create my DLLs? I am aware I need a common interface, but dont know exactly how to accomplish this with namespaces and interfaces and abstract classes.
Thanks!
I would recommend looking into the Managed Extensibility Framework. It was designed for this exact type of scenario.
For example, it is what Visual Studio uses for its extensibility, so add ins can be dynamically discovered and plugged in at runtime.
You can use a pre-written framework, but if you are looking for a "bare bones" solution, try this:
Create an interface (or set of interfaces, if you prefer) that contains all methods that the forms app will call, e.g. IPlugin. Put the interface(s) in a separate class library.
In each plugin DLL, create a public class that implements IPlugin.
In the forms app, decide what plugins to load and when to call them. This logic is entirely up to you.
Load a plugin like this, then call the interface members to accomplish what you want. You could read the plugin file and class names from app.config, a database, or calculate them via a naming convention, according to your requirements.
var pluginAssembly = Assembly.Load(pluginFileName);
var plugin = (IPlugin) pluginAssembly.CreateInstance(pluginClassName);
These methods have several overloads allowing more control over the process. For example, you can load the plugin assembly using an AssemblyName rather than a simple string. When instantiating the class, you can specify binding flags and a set of parameter values to pass to the class's constructor.
We build a lot of components, WinForms, Workflow activities etc, and something that we use a lot is the 'Designer' attribute.
The general practice during initial development is, the Designer attribute is used with the [Designer(typeof(DesignerType))] style to get things working - then later, this is converted to [Designer("AssemblyQualifiedTypeName")], which allows the designer DLL to be removed from the component's reference list - this removes the need for the component consumer to have to deploy the designer DLL with their product.
This practice of splitting the design-time, and run-time code into two seperate DLLs is common practice, and one that I am a proponent of.
A negative side effect, is the 'assembly qualified type name' will include the assembly version of the designer dll, so when the version is incremented, one must perform a 'search and replace' across the product to ensure they have updated all the 'loose references' to this designer.
Finally, my question:
Can anyone reccomend a best practice that doesnt rely on 'search and replace', which can manage all these references, to ensure they are always up to date?
We often get a lazy developer forgetting to update the reference string, resulting in a new version of the component linking to the previous version of the designer DLL - which of course doesnt get deployed, so design-time support is lost.
Perhaps some form of pragmas, macros, build script, magic attributes, I dont know, but there must be a better way of doing this.
Anyone? (thanks)
Why not create a single designer that uses something like the Managed Addin Framework or Activator.CreateInstance internally to pick and show a designer? With this technique, the Designer attribute would never have to change...
Do it like Microsoft does. Take a look at AssemblyRef class (System.Windows.Forms.dll) in Reflector.
I have created something like this and this.
In effect I have a dll which supplies me with a "styler" for my application - it contains all my basic styles as well as a factory to call StylerFactory.DefaultStyler.ApplyStyles(this) on an Application - which merges the supplied ResourceDictionaries with the existing. This way I don't need all the basic styles in my components, nor do I need explicit references to my sesource-xaml-files.
Now - while this is working real good. The Styles are (obviously) not visible during design-time
To my questions:
Was that approach wise, or would it have been better to deploy xaml-resources and use them in every app/window/control ?
Does someone see any possibility to apply my styles to the design-time display of VS2008 ?
In my opinion, it's an acceptable approach. The reason being, I haven't seen a better method.
In my own cases, I've loaded resource dictionaries at runtime using the code I described here, which I would assume would work for loading resources from other assemblies as well. The drawback is that the designer will not run this code first, meaning no style is applied by default, what you're experiencing.
To counteract this, I added a default <ResourceDictionary.MergedDictionaries> definition in each of my <Window.Resources> that I needed to edit at design-time. While this ends up being a bit redundant, this allowed me to have a working design-time Window while the proper MergedDictionary can be loaded later during runtime. Perhaps you can use this to find a better method.
What is a component class and where would I typically use one?
When I add a new item to my project in VS.NET 2008 one of the options is to add a component.
I am not even sure I understand what a component is - but I would sure like to find out a bit more about them.
Could somebody explain them to me or perhaps point me towards an online tutorial that would help me.
Well, generally speaking, a component is any part of a thing. Specifically in .NET, a component is a class that implements the IComponent interface, which indicates that a class can interact with it's logical container.
More often than not, you see this in the form of design support, in that classes interact with their host in the designer, but that's not a strict requirement.
Component Class is for sharing objects between applications.
Typically for dropping down object like outlook email to an application.
If you mean a class that inherits from System.ComponentModel.Component, like for example the System.Windows.Forms.BindingSource and strongly-typed DataSets, this will allow to drag an instance on the Visual Studio design surface (on a form in design-time) and set some properties using the property grid.
Once there is an instance of such component on the form it is discoverable by other components/controls. For example a BindingSource can be selected as a data source for a grid view or some other control.