Calburn Micro - IoC is not initialized in WPF designer - wpf

I have a WPF application, using Caliburn Micro, and StructureMap for DI.
On my window, I have a ContentControl, the name of which is a property on my view model - at runtime Caliburn successfully locates the correct view based on the type of this property and displays it in that area.
At design-time, though, an exception is thrown: "InvalidOperationException: IoC is not initialized.". Looking at the stack trace, its obvious that Caliburns ViewLocator is attempting to use IoC to create an instance of the view, but the IoC container is not initialized at design time.
So, the question is: How do you initialize Caliburn's IoC at design time?
EDIT:
Here is my UserControl declaration:
<UserControl x:Class="MyNamespace.Views.Checklist.ChecklistQuestionEditView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:vm="clr-namespace:MyNamespace.ViewModels.Checklist"
xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro.Platform"
d:DataContext="{d:DesignInstance Type=vm:ChecklistQuestionEditDesignerViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True"
d:DesignHeight="700" d:DesignWidth="1000">
And here is the ContentControl that causes the issue:
<ContentControl IsTabStop="False" Grid.Row="2" Grid.Column="0" Margin="12" Name="TranslationView"/>
This control is populated by Caliburn's Name conventions via this property in the view model:
private ChecklistQuestionTranslationViewModel _TranslationView;
public ChecklistQuestionTranslationViewModel TranslationView
{
get { return _TranslationView; }
set
{
if (_TranslationView != value)
{
_TranslationView = value;
NotifyOfPropertyChange(() => TranslationView);
}
}
}
If I remove the ContentControl line above from the XAML, all other designer functionality works as expected.
For some reason, you can't copy the exception message from the designer, so I am putting a screen shot here. You can see that Caliburn is attempting to use IoC to create an instance of the View. but I don't have 10 reputation, so I can't post my screenshot.

You might want to have a look at this SO thread I recently asked (and answered): up to now is working great for us.
The main points of that approach are:
Prepare a fake design-time version for each of your view-models, both the container/parent as well as the one mapped to the ContentControl of your view (the child).
Each design-time version has the empty constructor, no external dependencies to be set. It must not rely on DI/IoC container at all.
For every public property data-bound between view and original view-model, the design-time view-model should have a property with the same name ... not necessarily the same type.
This is the case of your child view-model mapped to the ContentControl: the real parent view-model has e.g. a property of type MyCommandBarViewModel, while the fake parent view-model has one of type MyDesignTimeCommandBarViewModel.
This might be applied to a whole visual tree of view-models, the leaves being view-models that just show simple property types (strings, numbers, etc.)
In order to have the Designer and Caliburn.Micro work together to generate those design-time versions, you need to add the following on the root UI element (Window, UserControl, ...):
<Window
d:DataContext="{d:DesignInstance Type=fake:YourDesignTimeViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True">

Related

Xaml: design a layout with dynamically visible components

In a mvvm application some areas inside a window (in reality it is a UserControl inside MainWindow) are dynamically displayed according to the user selections.
The changing blocks are inside Stackpanels, I have 4 of them and only one at a time is displayed. This is accomplished binding Visibility to a bool property and using the BooleanToVisibilityConverter.
I put all the alternate StackPanel inside parent control. It works correctly, but during design phase in Visual Studio I see all of them, so I have problems in figuring the final layout.
How can I easily create the layout having more controls which share the same window area and are displayed one at a time ?
Setting A Design Time Only Data Context
Developing XAML in the Studio Designer can be greatly simplified by setting the Design-Time Data Context.
One implementation is based on setting a duplicate DataContext which will be ignored during the final compilation.
To implement the switching, add to the ViewModel, a property that will inform the designer whether it can be used in Development Mode or not.
I use an MVVMLight situation for this example, but for this declared instance property IsInDesignMode and static property ViewModelBase.IsInDesignModeStatic.
Example:
using System.ComponentModel;
namespace DataContextDesignTime.Example
{
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _flag;
public bool Flag
{
get => _flag;
set
{
if (!Equals(_flag, value))
{
_flag = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Flag)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(NotFlag)));
}
}
}
public bool NotFlag => !Flag;
}
}
<Window x:Class="DataContextDesignTime.Example.ExamleWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DataContextDesignTime.Example"
mc:Ignorable="d"
Title="ExamleWindow" Height="450" Width="800">
<d:Window.DataContext>
<local:MyViewModel Flag="True" NotFlag="True"/>
</d:Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<StackPanel>
<Border Background="LightBlue" Height="200"
Visibility="{Binding Flag, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<Border Background="LightGreen" Height="400"
Visibility="{Binding NotFlag, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
</Window>
In this example, you can change property values in XAML or in the Property Browser.
And you will immediately see the work of your bindings, triggers, how the display for certain data changes.
Note
This may fail on more complex VMs/packages, but in general by setting the DataContext at design time is not difficult.
I need to recompile the project to see the changes in the properties.
The XAML Designer panel has an «Enable/Disable Project Code» button.
, but during design phase in Visual Studio I see all of them, so I have problems in figuring the final layout.
This problem is easily resolved by bringing up the Document Outline tab in visual studio. Once open, navigate to the visible tree and toggle the eyeball to visibly hide/unhide the control[s] one is not interested in; during design time only.

Use properties of the base control that is inside the UserControl

How can I use the properties of the controls that are inside a user control without having to use DependencyProperty?
Since, if for example I want to use all the properties of a button, I would have to declare all these?
And if there is another way without user control and it is the correct one, I would appreciate it if you answered it. (Google translator, sorry)
UserControl:
<UserControl x:Class="UserControls.UserControl01"
...
>
<Grid>
<Button x:Name="uc_btn" />
<TextBox x:Name="uc_txt" />
<DataGrid x:Name="uc_dtg" />
</Grid>
</UserControl>
Code using the UserControl:
<Window x:Class="UserControls.wnd02"
...
>
<Grid>
<local:UserControl01 uc_btn.Background="Red" uc_txt.Margin="10" uc_dtg.BorderThickness="5" Margin="90" />
<local:UserControl01 uc_btn.Background="Green" uc_txt.Margin="25" uc_dtg.BorderThickness="20" Margin="5" />
</Grid>
</Window>
It is not usual to do what you are asking.
Let's consider a usercontrol which is intended to work as if it is one single control. For example a time picker. This contains two sliders which increase/decrease hour and minute. You can also overtype in the hour and minute textboxes and there's a : between the two textboxes.
This usercontrol is all about the one property though. Time. You don't care what the minutes background is externally. If this changes it's internal to the usercontrol.
In this scenario you'd usually add a TimeSpan dependency property to the usercontrol and this is the only thing anything external to it uses.
Pretty much all commercial WPF development uses the MVVM pattern and that TimeSpan would be bound to a property in the parent view's viewmodel.
That's one scenario.
Another is where a usercontrol encapsulates a bunch of UI which is then re-usable.
Styling has scope so when you apply a style to say a Button in a window then that would apply to any Buttons in a usercontrol within it. Setting their properties.
There are also certain dependency properties marked as "inherits" whose values propogate down the visual tree.
One such is DataContext and it is this which most teams would use to deal with properties within a usercontrol.
Using MVVM there would be a MainWindowViewModel.
That would have (say ) a ChildUserControlViewModel property. That would be associated with usercontrol using a datatemplate specified datatype.
You'd then bind properties of whatever is in a usercontrol to properties of ChildUserControlViewModel or properties of MainWindowViewModel using RelativeSource binding.
ViewModel first is a common navigation and composition pattern for WPF. You should be able to find numerous blogs explain it better than I can in a SO post.
Here's one:
https://social.technet.microsoft.com/wiki/contents/articles/30898.simple-navigation-technique-in-wpf-using-mvvm.aspx

Grid's attached properties always available?

In the xaml for this window I deleted the Grid container and put a DockPanel.
Yet, I can access a Grid's attached properties from the DockPanel. How is this possible?
Thanks!
<Window x:Class="testWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="testWindow" Height="300" Width="300">
<DockPanel Grid.Column="2">
</DockPanel>
</Window>
Because the properties are not on the instance, but are attached - meaning they are defined statically on the Grid class, and that the values are stored in a property container outside of the normal property system.
If you have a DockPanel within a Grid, you use Grid.Column to set which column the DockPanel should be on. Hence, they can be very useful. Attached dependency properties can also be inherited from the parent tree.
For more information, read this link:
http://www.abhisheksur.com/2011/07/internals-of-dependency-property-in-wpf.html
If we take the Grid.Column example, the internals are that somewhere in the Grid class lies a definition like this:
public static readonly DependencyProperty ColumnProperty =
DependencyProperty.RegisterAttached(
"Column",
typeof(int),
typeof(Grid),
new PropertyMetadata(0));
The above code is in fact all that is needed to declare an attached dependency property. Note that there is no getter nor setter here and that the property is static. All it is, is a declaration of behavior - there is no logic to store or retrieve it.
This is because WPF has its own internal store for Dependency Properties (DPs). A normal DP has no backing fields on the classes either. In other words, all DPs are stored internally by WPF. However, WPF still keeps track of which values belong to which instances, so it is still possible to store a Width = 20 for TextBox1. It also means that it is possible to store values that aren't even defined on the classes themselves - as is the case with attached DPs.
Since there are no rules for which controls Grid.Column can be set on, it can be stored even on controls that are not children of a Grid control.

Defining type of viewmodel for usercontrol and then handing it from parent control

I'm trying to wrap my head around WPF and MVVM.
In my test application I have a MainViewModel with a ChildViewModel property.
Similarly I have a Window that instantiates a MainViewModel and has a child control that should receive MainViewModel.ChildViewModel
For my current application I have a Window with (snipped for brevity)
<Window.DataContext>
<vm:MainWindowViewModel />
</Window.DataContext>
<Window.Content>
<view:ChildView DataContext="ChildViewModel"/>
</Window.Content>
How do I have my ChildView usercontrol define that it requires a datacontext of the type ChildViewModel and also receive it?
Currently I create it by setting it like so:
<UserControl.DataContext>
<vm:ChildViewModel>
</UserControl.DataContext>
but this creates a new instance of the ChildViewModel.
I tried to make the question as bare boned as possible. Hope it's still clear
Googling turned up a LOT of (contesting) approaches, but I can't see the forest for the trees anymore.
Your UserControl doesn't need to specify it's own ViewModel - you're already creating one and binding it.
That being said, your binding should be specified as:
<view:ChildView DataContext="{Binding ChildViewModel}"/>
The confusion likely stems from the fact that there are two distinctly different approaches to MVVM. Creating the VM within the Xaml's <DataContext> tag is a "view-first" approach - the View is creating and instantiating the ViewModel.
You're currently working in more of a ViewModel-First approach (similar to my series on MVVM), where the ViewModel's create the other ViewModels, and the VIew just binds to them.
Personally, I find VM-first easier to maintain from a code standpoint, and often prefer it. View-first has the advantage of (potentially) providing a better design time experience, which is why many MVVM advocates use that approach.

Handle exceptions with WPF and MVVM

I am attempting to build an application using WPF and the MVVM pattern. I have my Views being populated from my ViewModel purely through databinding. I want to have a central place to handle all exceptions which occur in my application so I can notify the user and log the error appropriately.
I know about Dispatcher.UnhandledException but this does not do the job as exception that occur during databinding are logged to the output windows. Because my View is databound to my ViewModel the entire application is pretty much controlled via databinding so I have no way to log my errors.
Is there a way to generically handle the exceptions raised during databinding, without having to put try blocks around all my ViewModel public's?
Example View:
<Window x:Class="Test.TestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestView" Height="600" Width="800"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<StackPanel VerticalAlignment="Center">
<Label Visibility="{Binding DisplayLabel, Converter={StaticResource BooleanToVisibilityConverter}}">My Label</Label>
</StackPanel>
</Window>
The ViewModel:
public class TestViewModel
{
public bool DisplayLabel
{
get { throw new NotImplementedException(); }
}
}
It is an internal application so I do not want to use Wer as I have seen previously recommended.
The Binding implementation is designed to be fault tolerant and so it catches all the exceptions. What you could do is to activate the following properties in your bindings:
ValidatesOnExceptions = true
NotifyOnValidationError = true
See also the MSDN.
This causes to raise the attached Error property on the bound control.
However, this infrastructure is designed for validating the user input and show validation messages. I’m not sure if this is what you are doing.

Resources