views:

547

answers:

3

I want to write a POCO in XAML, and use a DataTemplate to display that object in the GUI at runtime. So far, so good; I know how to do all that.

Since I'll already have a DataTemplate that can transform my POCO into a WPF visual tree, is there any way to get the Visual Studio designer to play along, and have the Design View show me the POCO+DataTemplate's resulting GUI, as I edit the POCO's XAML? (Obviously the designer wouldn't know how to edit the "design view"; I wouldn't expect the Toolbox or click-and-drag to work on the design surface. That's fine -- I just want to see a preview as I edit.)

If you're curious, the POCOs in question would be level maps for a game. (At this point, I'm not planning to ship an end-user map editor, so I'll be doing all the editing myself in Visual Studio.) So the XAML isn't WPF GUI objects like Window and UserControl, but it's still not something where I would want to blindly bang out some XAML and hope for the best. I want to see what I'm doing (the GUI map) as I'm doing it.

If I try to make a XAML file whose root is my map object, the designer shows "Intentionally Left Blank - The document root element is not supported by the visual designer." It does this even if I've defined a DataTemplate in App.xaml's <Application.Resources>.

But I know the designer can show my POCO, when it's inside a WPF object. One possible way of accomplishing what I want would be to have a ScratchUserControl that just contains a ContentPresenter, and write my POCO XAML inside that ContentPresenter's Content property, e.g.:

<UserControl ...>
    <ContentPresenter>
        <ContentPresenter.Content>
            <Maps:Map .../>
        </ContentPresenter.Content>
    </ContentPresenter>
</UserControl>

But then I would have to be sure to copy the content back out into its own file when I was done editing, which seems tedious and error-prone, and I don't like tedious and error-prone. And since I can preview my XAML this way, isn't there some way to do it without the UserControl?

A: 

I'm fairly certain that you aren't going to get what you want here.

WPF won't process much in the way of logic in the design window. That includes (for the most part) DataTemplate and IValueConverter objects that you use in your XAML data bindings, since those objects usually work with (POCO) objects that are not instantiated until run-time.

This could explain why it works in the UserControl example, since you ARE clearly creating an instance of your Map POCO right there in the XAML. The designer window absolutely will not attempt to render anything that is based on bindings or templates that refer to objects that Visual Studio can't instantiate at design-time. This basically means that you can't have your objects show up in the design window if you are trying to create those objects in your C# (or whatever) code behind the scenes. Your back-end code cannot be run by the design window, because it has to be built by the compiler and run before any of it can execute. (Previous versions of Visual Studio use extreme workarounds to try and remedy this, and Microsoft no longer provides this support.) Markup languages like XAML don't have that restriction since they contain no logical execution sequence, so the design window can render them on the screen using only the parsed XAML markup.

In a nut-shell, I don't think the XAML design window was ever intended to be used the way you are trying to use it.

If you really want to be able to see your POCO in the designer, but you don't want to have to insert it into a UserControl with a ContentPresenter --- try deriving your POCO from an appropriate root-element that the designer can render, and adding a Serialize method to read/write it to/from files.

If these solutions don't work for you, then you are probably going to have to deal with Visual Studio not rendering your Map objects in the design window. Maybe this will give you some motivation to create that stand-alone map editor after all, even if you don't ship it out to the end-user. You may want to spend the time to write a simple editor, even if it's for your use only. Visual Studio won't replace your custom map editor - at least, not in any way that will be useful to you.

Giffyguy
I wasn't talking about creating the Map in C#. I was talking about having it as the XAML root element, in which case I'm creating it in XAML just as clearly as in the UserControl example. There's no reason VS *couldn't* render it with App.xaml DataTemplates. It just seems to explicitly disable that scenario, and I was hoping someone knew a way around it.
Joe White
Point taken. I personally wouldn't expect the design window to render anything under a DataTemplate of any kind, though I admit I don't know enough about them to say for sure that there isn't any way around it. I wish I could give you more solid advice, but I'm afraid that's all I've got. It's a shame there aren't more people answering XAML questions ...
Giffyguy
+2  A: 

I'm doing this right now, actually. Create a ResourceDictionary and reference it from the other XAML file. For example, make one file containing you plain old object, i.e.:

<Windows:ResourceDictionary>
  <Collections:ArrayList x:Key="PreferenceList">
    <NumericPreference id="server.port"
  helpText="The port on which the server should listen for incoming connections (default is 30588)"
  min="1"
  max="65535"
  step="1"
  displayName="Port"
  validationName="Port number" />
  </Collections:ArrayList>
</Windows:ResourceDictionary>

(where NumericPreference is replaced by your POCO), and then reference it like so:

<UserControl>
  <UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Preferences.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </UserControl.Resources>
  <Grid>
    <!-- Your code here -->
  </Grid>
</UserControl>

... But yes, you'd still need your "scratch user control" hooked up to it to see the designer result, but there's no copying and pasting involved. The key part here is the ResourceDictionary Source="YourStaticResource.xaml"

You can't have the map as the root element (the root element must be ResourceDictionary), but you can have it as the only child element of the ResourceDictionary.

To reference the resource, use, of course {StaticResource XXX} or {DynamicResource XXX} where XXX is the x:Key you gave the POCO in its XML file (in this case I gave the referenced POCO object, the ArrayList, the "PreferenceList" key)

Robert Fraser
I was hoping to be able to see the designer as I edited the POCO, whereas this would require me to Ctrl+Tab back and forth between the ResourceDictionary.xaml and the ScratchControl.xaml. But it may be the best VS can do.
Joe White
You can have two windows/tabs/dockable whatevers open in VS -- one open with the designer and one open with the ResourceDictionary xaml. All you need is a scarily big monitor. Open the designer and the xaml in tabs and right-click on one of the tabs, then choose "new horizontal tab group" or "new verticl tab group".
Robert Fraser
A: 

Good article, It provides basics in nice way to readers.

zahid nawaz