Using MEF to import a WPF DataTemplate? - wpf

I was looking at MEF as an extensibility framework, and I'm pretty much sold, except for one point:
Let's say I want to import both a ViewModel and a View to display it. I think the "right" way to do that is for the MEF part to export a ViewModel class, and a DataTemplate that displays the ViewModel. As an example, say you were building a Visio-like application and you want to import a library of shapes. Each shape needs a View defined in Xaml and a ViewModel that would wrap some underlying Model object.
Is this possible? What would the Import contract look like for the DataTemplate and how do I make WPF aware of the imported DataTemplate?

Yes, I was able to make this work in the following way:
In my host WPF application, I added this Import:
[ImportMany("ApplicationResources", typeof(ResourceDictionary))]
public IEnumerable<ResourceDictionary> Views { get; set; }
Then in my composite part, I declared a ViewModel, and a data template for the ViewModel in a regular ResourceDictionary Xaml file. Then I created a code behind for the ResourceDictionary, like this (in this example, the ViewModel is called ItemViewModel and the ResourceDictionary is called ItemView):
[Export("ApplicationResources", typeof(ResourceDictionary))]
public partial class ItemView : ResourceDictionary
{
public ItemView()
{
InitializeComponent();
}
}
For reference, the Xaml for the example ResourceDictionary looks like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyCompany.MyProduct"
x:Class="MyCompany.MyProduct.ItemView">
<DataTemplate DataType="{x:Type local:ItemViewModel}">
...
</DataTemplate>
</ResourceDictionary>
Then, back in my host WPF application, after I successfully compose and before I show the main window, I do this:
// Add the imported resource dictionaries
// to the application resources
foreach (ResourceDictionary r in Views)
{
this.Resources.MergedDictionaries.Add(r);
}
That seems to successfully apply the DataTemplate anywhere WPF sees an ItemViewModel.
EDIT: For anyone who's interested, I released an application framework called SoapBox Core as open source, and it uses this method extensively to import Views into the application resources. It works very well, and you can download the source yourself and take a look at how it works.

Related

binding combobox items to dictionary of enums

still pretty new at WPF and binding especially, but I have an enum which I will be using as properties on objects elsewhere in my project, but one of the very first kickoff points of the program will be the user selecting a single item from a combobox, which I want to match to the available enum options. I originally thought to have a dictionary object with the enum option as the key, and the value as a string for use in the UI presentation, and this is what I have been working towards. I have been searching around and thought I had it, but the combobox is populating blank.
I have a couple of questions;
Firstly, since I'm still not quite sure what is what in relation to binding, is this issue related to this post Target Exception Bug which I found in a comment on another question? If so, does this mean I'm barking up the wrong tree for the time being? And is there another way for me to achieve my goal?
Secondly, if its not related, have I missed something in the below code? I currently get no error in the output window and the project compiles fine.
Here's the enum (which lives in a separate namespace that has been added to the project references);
namespace WGM_lbr
{
public class Available_Wgms
{
private static Dictionary<Wgms,string> _wgmColl;
public static Dictionary<Wgms,string> WgmsCollection
{
get
{
return _wgmColl;
}
}
static Available_Wgms()
{
_wgmColl = new Dictionary<Wgms, string>() {
{Wgms.First, "First Dictionary item"},
//other Dictionary Items go here
}
}
public enum Wgms
{
First,
//other Enum options go here
}
}
}
My Resource declaration in app.xaml
<Application x:Class="The_First.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WGM="clr-namespace:WGM_lbr;assembly=WGM_lbr"
StartupUri="MainWindow.xaml">
<Application.Resources>
<BooleanToVisibilityConverter x:Key="b2v"/>
<WGM:Available_Wgms x:Key="WgmList"/>
</Application.Resources>
And finally the combobox and binding xaml (in case its relevant, this lives in a nest of wpf controls, up to a grid which lives on page, which is being loaded to mainwindow.xaml via a frame control using the page as the source. Both the page and mainwindow have declared the WGM namespace - I cut these out as this post is already long enough);
<ComboBox Name="cmbWgmSelector" Margin="5,0" ItemsSource="{Binding Source={StaticResource WgmList}}"/>
Any help/advice that can be provided is greatly appreciated.
Update the binding as below:
<ComboBox Name="cmbWgmSelector" Margin="5,0" DisplayMemberPath="Value" ItemsSource="{Binding Path=WgmsCollection, Source={StaticResource WgmList}}"/>

Generics in XAML views: What about the .xaml file (content of the generic class)?

I have been trying to implement a generic view in XAML, this kind of thing in the MyView.xaml.cs file:
public partial class MyView<T>: UserControl {
// content...
}
And I know that I have to use x:TypeArguments for then using MyView. That's right, there's documentation online about that.
But... What about putting something in the MyView*.xaml* file ?
Currently I have a standard:
<UserControl x:Class="Some.Name.Space.Views.MyView"
*bunch of namespaces declarations*
>
some content (a StackPanel, a grid, whatever...)
</UserControl>
But, of course, the content of the .xaml file is going to make a class MyView and not MyView<T>. And I just cannot find on the internet which specific keyword we have to use in the xaml to say we are declaring the content of a Generic view.
Thanks

How to use a custom user control in silverlight

I was searching for a 'waiting' animation for silverlight after I realized that GIF animations doesn't work in Silverlight. I found an excellent animation here. How can I use this in my application. Do I need to create any custom controls. I just want to place this over my dataview until the items gets populated.
Check out this implementation in Coproject on codeplex.
If you're using mvvm, you can wrap operations in a using. The BusyWatcher gets injected into the ViewModel using MEF.
[Import(RequiredCreationPolicy = CreationPolicy.Shared)]
public IBusyWatcher Busy { get; set; }
then:
using (Busy.GetTicket())
{
...
}
Create UserControl call it something sensible like WaitAnim1.
The sample you point to overuses Grids. The outer grid represent in your case the UserControl. Do the following to make your usercontrol from that original code:-
copy the xmlns:sys="clr-namespace:System;assembly=mscorlib" namespace to your UserControl element.
copy the whole Grid.Resources to directly under the <UserControl> tag and rename Grid.Resources to UserControl.Resources
copy whole <Grid x:Name="LayoutRoot" > element from the source code and replace the one in your usercontrol with it.
You now have a usercontrol that when displayed will show the animation.

Avoiding Visual Studio designer errors when WPF resource is defined in separate project

How can I avoid Visual Studio designer errors when a WPF resource is defined in separate project?
I have three projects in a composite WPF application: the main application, an "infrastructure" library, and a "module" library. The main application references the other projects via their output DLLs (the projects are not located in a single solution together).
I am defining a skin (some brushes and styles in a ResourceDictionary) in the "infrastructure" library. I would like the main application to select a skin and make it available to the entire application (via MergedDictionaries in App.xaml).
In my module I want to use the resources defined in the skin that the main application loads. If I reference the resource as if it were locally available like this:
Background={StaticResource MainBackgroundBrush}
almost everything works as desired. The exception is that Visual Studio's designer gets confused and tells me that "StaticResource reference 'MainBackgroundBrush' was not found". This effectively prevents me from using the designer.
What can I do to define a "skin" ResourceDictionary in a project, reference that skin in the main application, and then use its resources in a module project?
You could create your own ResourceDictionary class, inheriting from ResourceDictionary.
Then you can arrange that at design-time this custom ResourceDictionary loads some explicitly defined styles (i.e. those loaded from the app at runtime), whereas at runtime it does nothing at all.
The IsInDesignMode-Property could be evaluated for this.
Say you have such a class, called 'DesignTimeResourceDictionary', then you just use s.th. like
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<Util:DesignTimeResourceDictionary Source="SomeUriToYourResources"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
to load your resources at design-time and make the designer work.
At Runtime you can then make your DesignTimeResourceDictionary skip the loading of resources and achieve the desired behavior.
If you need, you could really create a copy of the real resources for this, or you can just create a dummy dictionary containing all the keys you need to keep the designer working.
One possible solution is to use DynamicResource rather than StaticResource. The Visual Studio 2008 designer simply displays the controls without any styling, like VS2010 beta 1 does when it cannot resolve a StaticResource.
Using DynamicResource is appropriate in situations where a particular style may change at runtime, like when skinning.
I found some related questions supporting this:
Assembly-wide / root-level styles in WPF class library
What’s the difference between StaticResource and DynamicResource in WPF?
WPF - Dynamic vs Static Resources
I also found someone who states that DynamicResource should be used whenever a resource is not local:
Static vs Dynamic Resources
I just want to extend Simon D. answer. What he is proposing is the solution that i am using right now. I just wanted to share complete source code. It is from this Trick To Use A ResourceDictionary Only When In Design Mode source.
public class DesignTimeResourceDictionary : ResourceDictionary
{
/// <summary>
/// Local field storing info about designtime source.
/// </summary>
private string designTimeSource;
/// <summary>
/// Gets or sets the design time source.
/// </summary>
/// <value>
/// The design time source.
/// </value>
public string DesignTimeSource
{
get
{
return this.designTimeSource;
}
set
{
this.designTimeSource = value;
if ((bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue)
{
base.Source = new Uri(designTimeSource);
}
}
}
/// <summary>
/// Gets or sets the uniform resource identifier (URI) to load resources from.
/// </summary>
/// <returns>The source location of an external resource dictionary. </returns>
public new Uri Source
{
get
{
throw new Exception("Use DesignTimeSource instead Source!");
}
set
{
throw new Exception("Use DesignTimeSource instead Source!");
}
}
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation Jump "
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml Jump "
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication1">
<Window.Resources>
<local:DesignTimeResourceDictionary DesignTimeSource="pack://application:,,,/BlueColors.xaml"/>
</Window.Resources>
<Grid>
<Button Background="{DynamicResource defaultBackground}"
HorizontalAlignment="Center" VerticalAlignment="Center">click me</Button>
</Grid>
</Window>

WPF code-behind for resources?

I'm working on a wpf application, and up until recently, I had a ResourceDictionary inside my main window's resources part of the xaml. The resource dictionary contained an DataTemplate that was used to style several listboxes in the window. The xaml for this datatemplate contained pointers to event handlers, eg:
<Button n:Name="btnClickMe" Content="Click Me!" LeftMouseButtonUp="btnClickMe_Click" />
I recently decided to split the content of the window up into separate user controls, and to move my ResourceDictionary into it's own file. But, of course, there isn't a code-behind file for a resource dictionary file. How can I wire this up, with things split up as I've described?
Thanks in advance!
You can add a code-behind to a ResourceDictionary; just make sure your class names are referenced correctly. For instance, in the ResourceDictionary if you were working with AppStyles.xaml the XAML file would have a class of:
x:Class="Client.App.Shell.themes.AppStyles"
In the code-behind, AppStyles.xaml.cs, you would make sure to have the class:
namespace Client.App.Shell.themes
{
public partial class AppStyles
...
You can add a new class and name it with the same name as your resource dictionary plus the .cs extension and Visual Studio will automatically set things up so it becomes the code behind file.
For example if you have a resource dictionary called Buttons.xaml, add a file called Buttons.xaml.cs.
You should consider using RoutedCommands, I am thinking.
there are many many resources online, here are a couple that might help you.
http://msdn.microsoft.com/en-us/library/ms752308.aspx
http://www.devx.com/DevX/Article/37893/0/page/1

Resources