a bit new to Prismv4 and MEF.
I went through the QuickStarts and tried to combine two of them together, but I can't seem to get it working.
First, I got a Bootstrapper to load the Shell Window.
public sealed class ClientBootstrapper : MefBootstrapper
{
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
//Add this assembly to export ModuleTracker (Shell is in this Assembly).
AggregateCatalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
}
protected override DependencyObject CreateShell()
{
return Container.GetExportedValue<Shell>();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Window)Shell;
Application.Current.MainWindow.Show();
}
}
This worked fine. The Shell window was shown and a nice Hello World message appeared. Then I tried to create a Region inside the Shell window so I can load a View into that region. I haven't even gotten this to work to even look at moving it to an outside assembly.
[ModuleExport(typeof(HelloWorldModule), InitializationMode = InitializationMode.OnDemand)]
public class HelloWorldModule : IModule
{
[Import(AllowRecomposition = true)]
private IRegionViewRegistry regionViewRegistry;
[ImportingConstructor()]
public HelloWorldModule(IRegionViewRegistry registry)
{
this.regionViewRegistry = registry;
}
public void Initialize()
{
regionViewRegistry.RegisterViewWithRegion("PrimaryRegion", typeof(Views.HelloWorldView));
}
}
The HelloWorld view (just a simple UserControl that contains a TextBlock) is not being loaded into the region! I guess I'm a bit lost here on how to load in my regions.
You can try this and it works for me, the Module class as follows:
[ModuleExport(typeof(HelloWorldModule))]
public class HelloWorldModule : IModule
{
[Import]
private IRegionManager regionManager;
public void Initialize()
{
Uri viewNav = new Uri("HelloWorldView", UriKind.Relative);
regionManager.RequestNavigate("PrimaryRegion", viewNav);
}
}
The View class as follows:
[Export("HelloWorldView")]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class HelloWorldView : UserControl
{
public HelloWorldView()
{
InitializeComponent();
}
}
The xaml in HelloWorldView
<UserControl x:Class="HelloWorldModule.HelloWorldView"
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"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock>Hello World</TextBlock>
</Grid>
</UserControl>
You will need
protected override void ConfigureAggregateCatalog()
{
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstapper).Assembly));
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(HelloWorldModule.HelloWorldModule).Assembly));
}
It looks like you're trying to use the view discovery approach?
Have you tried the following:
[ModuleExport(typeof(HelloWorldModule), InitializationMode = InitializationMode.OnDemand)]
public class HelloWorldModule : IModule
{
private IRegionManager regionManager;
[ImportingConstructor]
public HelloWorldModule(IRegionManager regionManager)
{
this.regionManager = regionManager;
}
public void Initialize()
{
this.regionManager.RegisterViewWithRegion("PrimaryRegion", typeof(Views.HelloWorldView));
}
}
Your ConfigureAggregateCatalog method in your bootstrapper needs to add the assembly that your view is in. Adding the line below to the end of the method should get you past your current problem.
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Views.HelloWorld).Assembly));
This can also be done in XAML in a ModuleCatalog.
Your Views.HelloWorld class will also need an [Export] attribute added to it.
It's hard to tell what's going wrong based on the information you share.
I would suggest looking at the examples and the reference implementation that comes with PRISM4. I guess the reference implementation and a little debugging should help you in finding the problem.
public class ModuleC : IModule
{
#region IModule Members
/// <summary>
/// Initializes the module.
/// </summary>
public void Initialize()
{
/* We register always-available controls with the Prism Region Manager, and on-demand
* controls with the DI container. On-demand controls will be loaded when we invoke
* IRegionManager.RequestNavigate() to load the controls. */
// Register task button with Prism Region
var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
regionManager.RegisterViewWithRegion("TaskButtonRegion", typeof(ModuleBTaskButton));
/* View objects have to be registered with Unity using the overload shown below. By
* default, Unity resolves view objects as type System.Object, which this overload
* maps to the correct view type. See "Developer's Guide to Microsoft Prism" (Ver 4),
* p. 120. */
// Register other view objects with DI Container (Unity)
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
container.RegisterType<Object, ModuleBRibbonTab>("ModuleBRibbonTab");
container.RegisterType<Object, ModuleBNavigator>("ModuleBNavigator");
container.RegisterType<Object, ModuleBWorkspace>("ModuleBWorkspace");
}
}
Related
I've just created a new project in VS - Custom Control. The control is Canvas based since I need some drawing. The code is mostly auto generated so I will not provide here all the project.
My target is to bind some events/handlers of the control. Unfortunately I didn't find any constructor. After searching the Internet I found a way to do that - to put the init code inside the OnApplyTemplate() overridden method. As for me it is strange idea to avoid constructor, or some init method, but anyway .... Ok, I know that logic is not MS prerogative, no problem. But the real problem is that this method never called. So my question - where should I put my init code or (if OnApplyTemplate the only option) how to make this method be called on the component start?
MyMap.cs
namespace MyControl
{
public class MyMap : Canvas
{
public static readonly DependencyProperty ZoomProperty = DependencyProperty.Register("Zoom",
typeof(float),
typeof(MyMap),
new PropertyMetadata(0.5f));
public float Zoom
{
get { return (float)GetValue(ZoomProperty); }
set { SetValue(ZoomProperty, value); }
}
static MyMap()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyMap), new FrameworkPropertyMetadata(typeof(MyMap)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.SizeChanged += Map_SizeChanged;
}
}
}
The Themes/Generic.xaml file content:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyControl">
</ResourceDictionary>
The AssemblyInfo.cs has the following lines:
[assembly: ThemeInfo(
ResourceDictionaryLocation.None,
ResourceDictionaryLocation.SourceAssembly
)]
Just add a constructor like this:
public class MyMap : Canvas
{
public MyMap()
{
SizeChanged += Map_SizeChanged;
}
...
}
I add an Usercontrol base class
my Base Class
public class UserControlBase : UserControl
{
protected IAppLogic app;
public MainWindow CurrentWindow{
get{
return (App.Current.MainWindow as MainWindow);
}
}
public UserControlBase()
{
var _app = IoC.Kernel.Get<IAppLogic>();
this.app = _app;
}
public void MainNavigate(Pages.PageBase p)
{
CurrentWindow.MainFrame.Content = p;
}
}
but the design does not shown
Browsing around some of the other questions, I found some of the reasons this can happen
Q1 WPF Designer “Could not create an instance of type”
Suround the code in your constructor with this:
if(!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
//code producing exception
}
The base class is of the abstract type
An exception is thrown in your constructor while loading the custom control. This goes back to 1.
Please share the stacktrace for us to help more.
I've made a WPF program with Caliburn Micro, where I used singleton classes for my global variables, which are used in many forms and controls.
Now I understand that static classes are not recommended, so I want to refactor them away using an IoC container.
But I am unsure of how can I bind, for example, a datagrid to a class managed by the IoC container from within my xaml.
Before, I had
<Datagid ItemSource = "Source={x:StaticResource statics.class.instance}" ...
How can I create a binding that works against the IoC container?
Here's one way of doing it:
The view: MyView.xaml
<UserControl x:Class="MyNamespace.MyView">
<DockPanel>
<Datagid Name="MyItems"/>
</DockPanel>
</UserControl>
The view model: MyViewModel.cs
namespace MyNamespace
{
class MyViewModel : PropertyChangedBase
{
public ObservableCollection<MyItem> MyItems { get; }
public MyViewModel(MyStaticClass myStaticClass)
{
MyItems = ConvertMyStaticClassToObservableCollection(myStaticClass);
}
ObservableCollection<MyItem> ConvertMyStaticClassToObservabeCollection(MyStaticClass myStaticClass)
{
...
}
}
}
Finally, you need to make sure to set up your static class as a singleton using your IoC container. Here's how you'd do it using SimpleInjector, inside MyBootstrapper.cs:
protected override void Configure()
{
_container = new Container();
_container.Register<IWindowManager, WindowManager>();
_container.Register<IEventAggregator, EventAggregator>();
_container.RegisterSingleton<MyStaticClass>();
_container.Verify();
}
in my C# WPF Project (working with VS2012) my goal is to use existing Data from a class in a new Window I created...
Therefore I added a new Window (WPF) to my Project and called it DijkstraWindow. In my MainWindow there is a Menu and when you click the suitable item the DijkstraWindow is opened. In my MainWindow.xaml.cs this is the Code to do this:
private void Dijkstra_Click(object sender, RoutedEventArgs e)
{
var DWindow = new DijkstraWindow();
DWindow.Show();
}
Now I need to access data (which is created while the application is running) and this is stored in a list which is stored in a class. But I have no idea how to do this.
I tried the following:
1.
Creating a new object in DijkstraWindow:
var mwvm = new MainWindowViewModel();
The data is accessible (in my new DijkstraWindow) but it just takes the data which is initialized when starting the application. So this is the wrong way. Because there a some list which is filled while the application is running. I want to use this data in my new Window.
2.
In my DijkstraWindow.xaml.cs I tried to inherit from the class where my data is, but then the compiler is complaining
"Partial declarations must not specify different base classes"
So I read you have also to changed your xaml file, so changed it to:
<local:MainWindowViewModel x:Class="Graphomat.DijkstraWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Graphomat"
Title="DijkstraWindow" Height="300" Width="300">
<Grid/>
</local:MainWindowViewModel>
This is also not working, then my DijkstraWindow has no information about the show method?
Could someone please help me out with this?
Thank you!
edit
Here ist the Class Declaration:
*/using somestuff */
namespace Graphomat
{
/// <summary>
/// Interaction logic for DijkstraWindow.xaml
/// </summary>
public partial class DijkstraWindow : MainWindowViewModel
{
public DijkstraWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
}
}
Tried to inherit from class "MainWindowViewModel", but this doesn't work because the xaml file..
The compiler is complaining because your view's type Graphomat.DijkstraWindow doesn't declare the same base type between the xaml and the .cs file. Your cs file likely says that it inherits from the Window type.
One way to transfer data between ViewModels is dependency injection. Consider the following:
public class FooView : Window
{
//require data from the parentview to the child view through dependency injection.
//very simplistic, might meet your needs. If you need a full view lifecycle, see MVVM frameworks like
//cliburn.micro
public FooView(INavigationData navigationData)
{
//do something with your data.
}
}
It is very common to use a base class for all the view models in you project. Consider that you are binding all your views to individual view models, it only makes sense that you would create a base implementation of INotifyPropertyChanged on a base class:
public class MainViewModel : BaseViewModel
{
}
public abstract class BaseViewModel : INotifyPropertyChanged
{
public object Model { get; set; }
#region PropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if(handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region Commands
public ICommand OpenFooWindowClicked
{
get
{
//implement your ICommand here... beyond the scope of the question.
}
}
#endregion
}
As far as the class problem is concerned, if you are following the typical MVVM naming convention, then it looks like you're trying to define your ViewModel in xaml. While that's not unheard of, you likely want to define your View in xaml.
Please do check out the SO question: MVVM: Tutorial from start to finish? The tutorials linked in that thread should get your head wrapped around the concepts vital to successful execution of the MVVM pattern.
I have this code behind:
CustomUserControl.xaml.cs
namespace MyProject
{
public partial class CustomUserControl<T> : UserControl
{
...
}
}
and this xaml:
CustomUserControl.xaml
<UserControl x:Class="MyProject.CustomUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Grid>
</Grid>
It doesn't work since the x:Class="MyProject.CustomUserControl" doesn't match the code-behind's generic class definition. Is there some way to make this work?
You can create generic "code-behind" file without XAML-file:
public class CustomUserControl<T>: UserControl
{ }
and than derive from it providing specific class as a parameter:
public partial class SpecificUserControl : CustomUserControl<Presenter>
{
public SpecificUserControl()
{
InitializeComponent();
}
}
XAML:
<application:CustomUserControl
x:TypeArguments="application:Presenter"
xmlns:application="clr-namespace:YourApplicationNamespace"
...
Unfortunately, it seems that Visual Studio designer doesn't support such generics until Visual Studio 2012 Update 2 (see https://stackoverflow.com/a/15110115/355438)
Haven't found my solution anywhere else so far.
The main difference is, that I have got one .xaml file
for the generic user control class and not one for each actual user control.
GenericUserControl.xaml.cs
using System.Windows.Controls;
namespace TestGenericUserControl
{
public abstract partial class GenericUserControl : UserControl
{
// If you use event handlers in GenericUserControl.xaml, you have to define
// them here as abstract and implement them in the generic class below, e.g.:
// abstract protected void MouseClick(object sender, MouseButtonEventArgs e);
}
public class GenericUserControl<T> : GenericUserControl
{
// generic properties and stuff
public GenericUserControl()
{
InitializeComponent();
}
}
// To use the GenericUserControl<T> in XAML, you could define:
public class GenericUserControlString : GenericUserControl<string> { }
// and use it in XAML, e.g.:
// <GenericUserControlString />
// alternatively you could probably (not sure) define a markup extension to instantiate
// it directly in XAML
}
GenericUserControl.xaml
<UserControl x:Class="TestGenericUserControl.GenericUserControl"
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">
<Grid>
<Label Content="hello" />
</Grid>
</UserControl>
Unfortunately XAML does not support generic code behind, thou you can walk around this.
See links below:
http://forums.silverlight.net/forums/p/29051/197576.aspx
Can I specify a generic type in XAML (pre .NET 4 Framework)?
May be generic controls will be supported natively in future versions of Visual Studuo with
XAML 2009.
I ended up with an extra helper class, this is not a UserControl. It does the job well for a simple custom UserControl that needs a Generic Type.
So the UserControl, for instance UCMoveObject, has an InitFunction that returns to me the Helper instance:
// In the UCMoveObjects UserControl Class.
public UCMoveObjectsHelper<T> InitUCMoveObject<T>(List<T> argAllList, List<T> argSelectedList)
{
return new UCMoveObjectsHelper<T>(this, argAllList, argSelectedList);
}
Then in the helper class I place all the code for making the user control work.
public class UCMoveObjectsHelper<T>
{
public UCMoveObjectsHelper(UCMoveObjects argUserControl, List<T> argAllList, List<T> argSelected)
{
_ucMoveObjects = argUserControl;
// Example reaching the usercontrol
_ucMoveObjects.listBox.SelectionChanged += LbAll_SelectionChanged;
// Do whatever I want with T
}
public List<T> ReturnSelected()
{
// Code that return a List<T>;
}
}
In the MainWindow.xaml i place a usercontrol in the window. Then in code I do the following:
_ucMovingObjectsHelper = ucMovingObjects.InitUCMoveObject<TblUsers>(tempListAll, tempListSelected);
And later in my code I can call:
var tempSelectedList = _ucMovingObjectsHelper.ReturnSelected();