Summary of WPF designer limitations and rules for WYSIWYG view creation? - c#

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?

Related

Is there a general way to avoid exceptions when editing XAML? [duplicate]

I am working without expression blend and just using the XAML editor in vs2010. The wisdom of this aside, I am increasingly seeing a need for design-time data binding. For simple cases, the FallbackValue property works very nicely (Textboxes and TextBlocks, etc). But especially when dealing with ItemsControl and the like, one really needs sample data to be visible in the designer so that you can adjust and tweak controls and data templates without having to run the executable.
I know that ObjectDataProvider allows for binding to a type, and thus can provide design-time data for visualizing, but then there is some juggling to allow for the real, run-time data to bind without wasting resources by loading loading both the design time, dummied data and the runtime bindings.
Really what I am wanting is the ability to have, say, "John", "Paul", "George", and "Ringo" show up in the XAML designer as stylable items in my ItemsControl, but have real data show up when the application runs.
I also know that Blend allows for some fancy attributes that define design time binding data that are effectively ignored by WPF in run-time conditions.
So my questions are:
1. How might I leverage design-time bindings of collections and non-trivial data in the visual studio XAML designer and then swap to runtime bindings smoothly?
2. How have others solved this design-time vs. runtime data problem? In my case, i cannot very easily use the same data for both (as one would be able to with, say, a database query).
3. Are their alternatives to expression blend that i could use for data-integrated XAML design? (I know there are some alternatives, but I specifically want something I can use and see bound sample data, etc?)
Using VS2010 you can use Design-Time attributes (works for both SL and WPF). I usually have a mock data-source anyway so it's just a matter of:
Adding the namespace declaration
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Adding the mock data context to window/control resources
<UserControl.Resources>
<ViewModels:MockXViewModel x:Key="DesignViewModel"/>
</UserControl.Resources>
Setting design-time data context
<Grid d:DataContext="{Binding Source={StaticResource DesignViewModel}}" ...
Works well enough.
As an amalgam of Goran's accepted answer and Rene's excellent comment.
Add the namespace declaration.
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Reference your design time data context from code.
<Grid d:DataContext="{d:DesignInstance Type=ViewModels:MockXViewModel, IsDesignTimeCreatable=True}" ...
I use this approach for generating design time data with .NET 4.5 and Visual Studio 2013.
I have just one ViewModel.
The view model has a property IsInDesignMode which tells whether design mode is active or not (see class ViewModelBase).
Then you can set up your design time data (like filling an items control) in the view models constructor.
Besides, I would not load real data in the view models constructor, this may lead to issues at runtime, but setting up data for design time should not be a problem.
public abstract class ViewModelBase
{
public bool IsInDesignMode
{
get
{
return DesignerProperties.GetIsInDesignMode(new DependencyObject());
}
}
}
public class ExampleViewModel : ViewModelBase
{
public ExampleViewModel()
{
if (IsInDesignMode == true)
{
LoadDesignTimeData();
}
}
private void LoadDesignTimeData()
{
// Load design time data here
}
}
Karl Shifflett describes an approach that ought to work equally well for VS2008 and VS2010:
Viewing Design Time Data in Visual Studio 2008 Cider Designer in WPF and Silverlight Projects
Laurent Bugnion has a similar approach that focuses on Expression Blend. It might work for VS2010, but I haven't confirmed this yet.
Simulating data in design mode in Microsoft Expression Blend
Maybe the new design-time features of Visual Studio 2010 and Expression Blend 4 are an option for you.
How it works is shown in the BookLibrary sample application of the WPF Application Framework (WAF). Please download the .NET4 version.
Similar to the top rated answer, but better in my opinion: You can create a static property to return an instance of design data and reference it directly from XAML like so:
<d:UserControl.DataContext>
<Binding Source="{x:Static designTimeNamespace:DesignTimeViewModels.MyViewModel}" />
</d:UserControl.DataContext>
This avoids the need to use UserControl.Resources. Your static property can function as a factory allowing you to construct non-trivial data types - for example if you do not have a default ctor, you can call a factory or container here to inject in appropriate dependencies.
Using Visual Studio 2017 I have been trying to follow all of the guides and questions such as this and I was still facing a <ItemsControl> which simply did not execute the code I had inside the constructor of a DesignFooViewModel which inherits from FooViewModel. I confirmed the "did not execute" part following this "handy" MSDN guide (spoiler: MessageBox debugging). While this is not directly related to the original question, I hope it will save others a lot of time.
Turns out I was doing nothing wrong. The issue was that my application needs to be built for x64. As the Visual Studio is still in 2018 a 32-bit process and apparently cannot spin a 64-bit host process for the designer part it cannot use my x64 classes. The really bad thing is that there are no errors to be found in any log I could think of.
So if you stumble upon this question because you are seeing bogus data in with your design time view model (for example: <TextBlock Text="{Binding Name}"/> shows up Name no matter you set the property to) the cause is likely to be your x64 build. If you are unable to change your build configuration to anycpu or x86 because of dependencies, consider creating a new project which is fully anycpu and does not have the dependencies (or any dependencies). So you end up splitting most or all but the initialization parts of the code away from your "WPF App" project into a "C# class library" project.
For the codebase I am working on I think this will force healthy separation of concerns at the cost of some code duplication which is probably net positive thing.
I liked jbe's suggestion, specifically to look at how they do it in the WAF framework sample apps - they use separate mock/sample view models in a DesignData folder and then have a line like this in the XAML:
mc:Ignorable="d"
d:DataContext="{d:DesignInstance dd:MockHomeViewModel, IsDesignTimeCreatable=True}"
(where dd points to the .DesignData namespace where MockHomeViewModel lives)
It's nice and simple (which I like!) and you can inherit from the real VMs and just provide dummy data. It keeps things separate as you don't need to pollute your real VMs with any design time only code. I appreciate things might look quite different for a large project utilising IOCs etc but for small projects it works well.
But as joonas pointed out, it seems not to work with x64 builds in VS2017 and this still seems to be the case with VS2019 (I'm using V2019 16.6 Community edition). It's not fiddly to get working to start off with but can cause some head scratching when after making a change (or as is usually the case, several changes!) it suddenly stops working.
For anybody trying it, I would recommend creating a new simple WPF project (say one view, one view model, one mock vm) and play around with it; get it working and then break it. I found sometimes, no amount of solution cleans and rebuilds would fix it, the only thing that worked was closing VS down and restarting, and suddenly my design time data came back!

How to provide intellisense with the datacontext type in a resharper plugin?

When writing a wpf prism app, I use the ViewModelLocator to automatically create the datacontext when needed. While this works great, there's no intellisense help unless I add a designtime datacontext (d:DataContext="{d:DesignInstance viewModels:MyViewModel}"), but that somewhat defeats the purpose of automatically discovering and connecting the viewmodel.
I image something like this: a resharper plugin that looks for ViewModelLocator.AutowireViewModel="True" in the xaml, fetches the class name, derives the viewmodel type and then tells intellisense to use this type as datacontext.
Question: is it possible for a resharper plugin to tell intellisense what is the type of the datacontext without the designtime datacontext?
Ancillary question: can you give a complete resharper sdk beginner a hint on how to accomplish this?
Unfortunately, that part of ReSharper is not extensible - it will only work with data set in the file. There is an issue suggesting extending by use of annotations, which is a nice idea - you can vote on it, add details and track: RSRP-385725

Regarding Visual Studio Forms Method Calling From Program.cs and general logic advice

I'm trying to implement Blackjack via Visual Studio, but have just been introduced to it. Suppose I have a PictureBox representing a card in a hand. This box starts with an image of a face-down card, representing a card slot that hasn't been dealt to yet. I have a function in my Form object that changes the PictureBox image to another card image resource based on an integer parameter. This is all pretty standard.
What I'm having trouble with is actually calling the method from main. I could create a new Form object and set the auto-generated one to invisible, but I'd rather work with the form that's auto-generated. Should I just put all the game logic in the Form1.cs file? Does the auto-generated form object have some default name I can use?
I realize this seems pretty novice level, but it seems like Microsoft's support documentation would prefer you create entire projects from the designer view and doesn't help much for actually coding.
The typical model for a simple Forms program is to allow the Main() method in Program.cs to remain in its default form: set some things up, create an instance of your primary Form subclass (the class name by default will be Form1), and pass that to the Application.Run() method.
It is good design to have a "controller" object outside of the UI object. But especially if you are starting out, you may well find it simpler and easier to understand if that "controller" logic is also in your primary Form subclass.
In that case, yes…all of the code winds up in the one .cs file, and indeed in the one object.
Even with the controller logic in the Form object, you will still find it useful to keep the code that is essentially controller logic separate from that which is user-interface logic, and to use the C# #region directive to label these sections of code. That will help you keep a mental model that still separates the two roles within the same class.
Beyond this, there are lots of differing opinions, from the complete "shoot-from-the-hip" approach, to the extremely strict and rigorous adherence to specific design patterns. But the above is consistent with the pattern that the Visual Designer leads you to, and so is a fine place for beginners to start.

DesignerAttribute in WPF?

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)

Strongly Typed Controls in .NET

I am working on a Windows Forms app for quite some time now, and I really find myself doing more typecasts in the GUI code than I ever did in my underlying business code.
What I mean becomes apparent if you watch the ComboBox control that accepts some vague "object" as it's item.
Then you go off and may display some DisplayMember and a ValueMember and so on.
If I want to retrieve that value later I need to typecast my object back to what it was. Like with strings getting the value takes
string value = (string)combobox1.SelectedItem;
Since there are generics in the Framework for quite some time now, I still wonder why in the Hell not one control from the standard toolbox is generic.
I also find myself using the .Tag property on ListViewItems all the time to keep the displayed domain object. But everytime I need to access that object I then need another typecast.
Why cant I just create a ComboBox or ListView with items of type ListViewItem
Am I missing something here or is this just another example of not perfectly well thought through controls?
While the criticism of "didn't use generics" can't be fairly applied to controls developed before their existence... one must wonder about WPF controls (new in .NET 3.0, after generics in .NET 2.0).
I checked out the AddChild method in ComboBox. It takes an object parameter (ugh).
This control is intended to be used primarily via XAML. Was this done this way because there is no way to specify a type parameter in XAML? (aside, is there no way to specify a type parameter in XAML?)
Sorry to have no definitive "Why" answer, just sharing the common misery of needing to cast when working with the UI.
I dont think you're missing anything.
It's just that these classes were created back in the pre-Generics days, and WinForms is simply not cutting edge enough for MS to spend a lot of time changing or extending the API.
I often create wrapper classes for controls. This allows me to use generics. This is often in conjunction with Reflection, which is not type safe at compile time, but can be at run time.
A common source of this problem, I think, is not separating your view/presentation logic from your in-memory data model logic. Which, unfortunately, is an architecture fault that WinForms and the Visual Studio GUI designer are complicit in.
WinForms and the VS designer do not encourage the programmer to separate the management of their data objects from the form classes themselves. It would probably be better if the ComboBox ListViewItem objects didn't offer any support for arbitrary objects, either via generics or Object collections..
Unless you are hacking together something of limited use and lifetime, you should try to avoid storing references to individual data objects right in your controls or forms. They should be managed separately, and if they need to be referenced, it should be done via a model management class designed for the particular type of view class you're working with.
A simple-ish bandage for the problem, though, might be to "map" the text representations that you place into the ComboBox or ListView to the original objects, using a Dictionary field member on your Form class. It's not an ideal solution, but gives you at least a half-step of indirection between your data and your UI controls, which can make your code easier to maintain.
Edit: This is admittedly separate from the ListViewItemCollection class exposing Object instances... The official defense is likely to be that they wanted to support the standard IEnumerable and ICollection interfaces. But there's no reason they couldn't have also provided type-specific overrides of these methods, since it is designed explicitly to store ListViewItem instances. So I have no answer for you on that particular question.
Well, if you data-bind your controls to a DataBindingSource, you can get at your data that way, but AFAIK that's still not strongly typed. If you are displaying multiple parameters/aspects of a single business object, you can bind to that, then access the (strongly typed) members instead -- of course, this all goes back to Turbulent Intellect's answer, which is better separation between model and view. Still, I agree that generic-based typing would help.
It is possible (you can make your own generic controls, if you wish), but the form designer that comes with Visual Studio will freak out if you do this. You'll have to do stuff without it.
You aren't the first one to think of this, and Microsoft has already received a fair share of criticism from the public for this. Let's hope they add support for this in the future.

Categories