Unity: Problem with resolving RIA DomainContext - silverlight

I am using PRISM 4 and got my head around almost all features, however as soon as I would like to inject my DomainContext class (RIA) into my view model, the hell breaks loose. :) It would be great if an experienced Unity/Prism developer could give me an advice how to proceed.
Within my bootstrapper, I am registering the required class in Unity Container like this:
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType<SCMDomainContext>();
}
Within the NavigationModule, I have the following in the ctor to register the NavigationView with a particular region.
public NavigationModule(IUnityContainer container, IRegionManager regionManager)
{
_container = container;
_regionManager = regionManager;
_regionManager.RegisterViewWithRegion(Constants.NavRegion, () => _container.Resolve<NavigationView>());
}
The View takes the View Model as dependency:
public NavigationView(NavigationViewModel viewModel)
{
InitializeComponent();
Loaded += (s, e) =>
{
DataContext = viewModel;
};
}
The ViewModel has the following:
public NavigationViewModel(SCMDomainContext context)
{
_context = context;
ConstructCommon();
}
As soon as I comment this ctor out and put a en empty ctor, it is all fine, for some reason I can't resolve the SCMDomainContext class. Which is the one you add to have the Domain Context created for you provided by Ria Services.
Since I am using Silverlight, I can't see the stack trace to follow the exception, all I get is this message on a page. What am I missing please?
Microsoft JScript runtime error: Unhandled Error in Silverlight Application An exception occurred while initializing module 'NavigationModule'.
- The exception message was: Activation error occured while trying to get instance of type NavigationModule, key ''
Check the InnerException property of the exception for more information. If the exception occurred
while creating an object in a DI container, you can exception.GetRootException() to help locate the
root cause of the problem. at Microsoft.Practices.Prism.Modularity.ModuleInitializer.HandleModuleInitializationError(ModuleInfo moduleInfo, String assemblyName, Exception exception)
at Microsoft.Practices.Prism.Modularity.ModuleInitializer.Initialize(ModuleInfo moduleInfo)
at Microsoft.Practices.Prism.Modularity.ModuleManager.LoadModulesThatAreReadyForLoad()
at Microsoft.Practices.Prism.Modularity.ModuleManager.IModuleTypeLoader_LoadModuleCompleted(Object sender, LoadModuleCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.RaiseLoadModuleCompleted(LoadModuleCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.HandleModuleDownloaded(DownloadCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.IFileDownloader_DownloadCompleted(Object sender, DownloadCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.FileDownloader.WebClient_OpenReadCompleted(Object sender, OpenReadCompletedEventArgs e)
at System.Net.WebClient.OnOpenReadCompleted(OpenReadCompletedEventArgs e)
at System.Net.WebClient.OpenReadOperationCompleted(Object arg)
Your help on this is highly appreciated,
Kave

I can't see much wrong here. But having said that, I'm using the Initialize method from the interface in the following way to register types and views for regions:
#region properties
[Dependency]
public IUnityContainer Container { get; set; }
[Dependency]
public IRegionManager RegionManager { get; set; }
#endregion
public virtual void Initialize()
{
this.Container.RegisterType<NavigationViewModel>(new ContainerControlledLifetimeManager());
this.Container.RegisterType<NavigationView>(new ContainerControlledLifetimeManager());
this.RegionManager.RegisterViewWithRegion(Constants.NavRegion, () => this.Container.Resolve<NavigationView>());
}
Not sure whether it makes a difference if you don't explicitly register the ViewModel and the View type. Personally I prefer to have control over the way how a type gets resolved by the container.

In fact its best to create a layer for the DomainContext like this. Then its easily resolvable by an IoC:
public class ContactModuleService : IContactModuleService
{
readonly SCMDomainContext _context = new SCMDomainContext();
#region Implementation of IContactModuleService
public EntitySet<Contact> Contacts
{
get { return _context.Contacts; }
}
public EntityQuery<Contact> GetContactsQuery()
{
return _context.GetContactsQuery();
}
public SubmitOperation SubmitChanges(Action<SubmitOperation> callback, object userState)
{
return _context.SubmitChanges(callback, userState);
}
public SubmitOperation SubmitChanges()
{
return _context.SubmitChanges();
}
public LoadOperation<TEntity> Load<TEntity>(EntityQuery<TEntity> query, Action<LoadOperation<TEntity>> callback, object userState) where TEntity : Entity
{
return _context.Load(query, callback, userState);
}
public LoadOperation<TEntity> Load<TEntity>(EntityQuery<TEntity> query) where TEntity : Entity
{
return _context.Load(query);
}
#endregion
}

Related

Passing arguments to RoutedEventHandler

I have a UserControl with a Slider which I'd like to handle RoutedEvent. Button was no problem and it works fine, since there are no args.
This is my Button handler:
public static readonly RoutedEvent OnOffClickEvent = EventManager.RegisterRoutedEvent(
nameof(OnOffClick), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ColorLightControl));
public event RoutedEventHandler OnOffClick
{
add => AddHandler(OnOffClickEvent, value);
remove => RemoveHandler(OnOffClickEvent, value);
}
private void ButtonOnOff_Click(object sender, RoutedEventArgs e) =>
RaiseEvent(new RoutedEventArgs(OnOffClickEvent));
But banging my head on the table because can't handle Slider's ValueChanged event. This is what I coded but it doesn't work on execution.
public static readonly RoutedEvent ColorSlideEvent = EventManager.RegisterRoutedEvent(
nameof(ColorSlide), RoutingStrategy.Bubble, typeof(EventHandler<RoutedPropertyChangedEventArgs<double>>), typeof(ColorLightControl));
public event EventHandler<RoutedPropertyChangedEventArgs<double>> ColorSlide
{
add => AddHandler(ColorSlideEvent, value);
remove => RemoveHandler(ColorSlideEvent, value);
}
private void SliderColor_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) =>
RaiseEvent(new RoutedPropertyChangedEventArgs<double>(e.OldValue, e.NewValue, ColorSlideEvent));
I get this error and I'm pretty sure it's because ColorSlide is not declated as RoutedEventHandler but not sure how to pass args. Any help appreciated. Thanks
System.InvalidCastException: 'Unable to cast object of type 'System.EventHandler1[System.Windows.RoutedPropertyChangedEventArgs1[System.Double]]' to type 'System.Windows.RoutedPropertyChangedEventHandler`1[System.Double]'.'
The error message tells the whole story:
either use the appropriate event handler RoutedPropertyChangedEventHandler (instead of EventHadler<T>) or create a custom class that extends RoutedEventArgs.
The reason is that RoutedPropertyChangedEventArgs<T> overrides the virtual RoutedEventArgs.InvokeEventHandler method (which is highly recommended to do so). In this override you usually cast the Delegate to a specific type (in place of reflection). This is where the coupling between RoutedPropertyChangedEventArgs and RoutedPropertyChangedEventHandler is created and where the exception you have encountered is thrown (as a result of the failed explicit type cast).
Since the default implementation of RoutedEventArgs.InvokeEventHandler uses reflection, you are advised to provide a specialized override to improve the performance (as you eliminate the reflection required to write a generic event invocator).
An example to create a custom routed event args type including the recommended RoutedEventArgs.InvokeEventHandler override:
// Optional delegate as an alternative to 'EventHandler<SliderValueChangedRoutedEventArgs<TValue>>'.
public delegate void SliderValueChangedRoutedEventHandler<TValue>(object sender, SliderValueChangedRoutedEventArgs<TValue> e);
// Routed event args that supports the 'SliderValueChangedRoutedEventHandler<TValue>' delegate
// and the 'EventHandler<SliderValueChangedRoutedEventArgs<TValue>>' delegate
public class SliderValueChangedRoutedEventArgs<TValue> : RoutedEventArgs
{
public SliderValueChangedRoutedEventArgs()
{
}
public SliderValueChangedRoutedEventArgs(RoutedEvent routedEvent) : base(routedEvent)
{
}
public SliderValueChangedRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
{
}
public SliderValueChangedRoutedEventArgs(RoutedEvent routedEvent, object source, TValue value) : base(routedEvent, source)
{
this.Value = value;
}
protected override void InvokeEventHandler(Delegate genericHandler, object genericTarget)
{
if (genericHandler is EventHandler<SliderValueChangedRoutedEventArgs<TData>> defaultHandler)
{
defaultHandler.Invoke(genericTarget, this);
}
else
{
var strongTypedHandler = (SliderValueChangedRoutedEventHandler<TData>)genericHandler;
strongTypedHandler.Invoke(genericTarget, this);
}
}
public TValue Value { get; }
}

Open new window on click in WPF, Ninject and Caliburn.Micro

I'm trying to set up a WPF app to call the new window on a menu click with the data provider interface injected into the new viewmodel.
Followed many tutorials and created the Bootstrapper for Caliburn, a service locator and module for ninject. So far the main view doesn't need the IDataProvider but I'd like to open a new window on click event.
The Bootstrapper:
public class Bootstrapper : BootstrapperBase
{
public Bootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<MainScreenViewModel>();
}
}
The Service Locator and Module:
public class ServiceLocator
{
private readonly IKernel _kernel;
public ServiceLocator()
{
_kernel = new StandardKernel(new ServiceModule());
}
public MainScreenViewModel MainScreenViewModel => _kernel.Get<MainScreenViewModel>();
public NewLayoutViewModel NewLayoutViewModel => _kernel.Get<NewLayoutViewModel>();
}
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<ISqlite>().To<Sqlite>();
Bind<IDataProvider>().To<DataProvider>();
}
}
And this is where I got stuck:
public class MainScreenViewModel : Conductor<object>
{
private IWindowManager _windowManager;
public MainScreenViewModel()
{
_windowManager = new WindowManager();
}
public void NewLayout()
{
_windowManager.ShowWindow(new NewLayoutViewModel());
}
}
since the NewLayoutViewModel requires the IDataProvider.
Not sure, what am I missing, but in my understanding Ninject should take care of this di for NewLayoutViewModel.
Found a good solution from Tim Corey on YouTube.
Basically the answer is, if you not insist Ninjet, use Caliburn.Micro's build-in DI solution "SimpleContainer".

Global handling exception in WPF app with Caliburn.Micro

Hi I try implement solution from this site im my WPF app for global exception handling.
http://www.codeproject.com/Articles/90866/Unhandled-Exception-Handler-For-WPF-Applications.aspx
I use Caliburn Micro as MVVM framework. Service I have in external assembly and it is injected in view model class with MEF.
Here is my implementation for global exception handling in WPF app.
App.xaml
DispatcherUnhandledException="Application_DispatcherUnhandledException"
Startup="Application_Startup"
App class:
public partial class App : Application
{
private IMessageBox _msgBox = new MessageBoxes.MessageBoxes();
public bool DoHandle { get; set; }
private void Application_Startup(object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private void Application_DispatcherUnhandledException(object sender,
System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (DoHandle)
{
_msgBox.ShowException(e.Exception);
e.Handled = true;
}
else
{
_msgBox.ShowException(e.Exception);
e.Handled = false;
}
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.ExceptionObject as Exception;
_msgBox.ShowException(ex);
}
}
Service method from external assembly:
public void ServiceLogOn()
{
try
{
}
catch (Exception ex)
{
throw ex;
}
}
This service method is call in view model class for example on button click event:
[Export(typeof(ILogOnViewModel))]
public class LogOnViewModel : Screen, ILogOnViewModel
{
public void LogOn()
{
_service.ServiceLogOn();
}
}
I run WPF app in Visual Studio and produce exception with message "Bad credentials" in ServiceLogOn method.
I expect that I see the message box with the exception.
But Visual Studio stop debuging app and show exception in service method in service project.
So I try run WPF from exe file and produce same exception in ServiceLogOn method.
I get this error:
Exception has been throw by target of an invocation.
Any exception from view model class is not handled in methods:
Application_DispatcherUnhandledException
or CurrentDomain_UnhandledException.
in App class.
What I do bad?
EDITED with Simon Fox’s answer.
I try implement in MEF bootstraper advice of Simon Fox’s, but I still something do wrong.
I move handle logic for exception to OnUnhandledException method in bootstraper class.
Here is my code from bootstraper class:
public class MefBootStrapper : Bootstrapper<IShellViewModel>
{
//...
private IMessageBox _msgBox = new MessageBoxes.MessageBoxes();
public bool DoHandle { get; set; }
protected override void OnUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (DoHandle)
{
_msgBox.ShowException(e.Exception);
e.Handled = true;
}
else
{
_msgBox.ShowException(e.Exception);
e.Handled = false;
}
}
//...
}
I bind some method from view model on button and throw new exception. Something like this:
public void LogOn()
{
throw new ArgumentException("Bad argument");
}
But result is sam, I test app out of Visual Studio and get this exception.
Exception has been throw by target of an invocation.
Caliburn.Micro has built in support for hooking unhandled exceptions. The Bootstrapper class (which every Caliburn project requires) sets this up for you and provides the virtual OnUnhandledException method.
In your custom BootStrapper you must override OnUnhandledException to perform any custom actions for unhandled exceptions in your app. Note that you will most likely have to marshal actions such as displaying a message box to the UI thread (Caliburn enables this easily via Execute.OnUIThread).
You may also have an issue in the way your service moves exceptions to the client, but without any details of how the service is implemented/hosted/etc I cannot help. Are you using WCF to do SOAP? Are you using FaultContracts?

How can I turn binding errors into runtime exceptions?

Just as there is "treat warning as errors" set in our projects to catch early possible problems, I would love to have a runtime exception to catch them early.
I have recently been bit by this problem and I would have been glad to have this.
Can it be done? And if yes, how?
You could hook into the PresentationTraceSources collection with your own listener:
public class BindingErrorListener : TraceListener
{
private Action<string> logAction;
public static void Listen(Action<string> logAction)
{
PresentationTraceSources.DataBindingSource.Listeners
.Add(new BindingErrorListener() { logAction = logAction });
}
public override void Write(string message) { }
public override void WriteLine(string message)
{
logAction(message);
}
}
and then hook it up in code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
BindingErrorListener.Listen(m => MessageBox.Show(m));
InitializeComponent();
DataContext = new string[] { "hello" };
}
}
Here is the XAML with a binding error
<Grid>
<TextBlock Text="{Binding BadBinding}" />
</Grid>
I implemented a solution very similar to the one proposed by Dean Chalk:
Derived a TraceListener that throws instead of logging
Added that listener to PresentationTraceSources.DataBindingSource
Please see the complete solution on GitHub, it includes a demo application and a unit test project.
First add this class to your project:
using System.Diagnostics;
namespace WpfTestApp
{
public class BindingErrorListener : TraceListener
{
public static void Register()
{
PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorListener());
}
public override void Write(string message)
{
}
public override void WriteLine(string message)
{
#if DEBUG
throw new System.Exception(message);
#endif
}
}
}
Then call the Register method in your App.xaml.cs class:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BindingErrorListener.Register();
// ...
}
}
This way, (by throwing an exception) if you have any binding errors then you will be aware of those errors in the first place, that is, as soon as you start (F5) your application. If you wish, you can log those by injecting your logger object in the BindingErrorListener constructor.

Silverlight 2 and the MVP Pattern

Any ideas on how i get MVP working with Silverlight? How Do I get around the fact there is no load event raised?
This the view I have:
public partial class Person: IPersonView
{
public event RoutedEventHandler Loaded;
public Person()
{
new PersonPresenter(this);
InitializeComponent();
}
public Person Person
{
set { Person.ItemsSource = value; }
}
}
And my presenter:
public class PersonPresenter
{
private readonly IPersonView _view;
private readonly ServiceContractClient _client;
public PersonPresenter(IPersonView view)
{
_client = new ServiceContractClient();
_view = view;
WireUpEvents();
}
private void WireUpEvents()
{
_view.Loaded += Load;
}
private void Load(object sender, EventArgs e)
{
_client.GetPersonCompleted += Client_GetPerson;
_client.GetPersonAsync();
}
private void Client_GetPerson(object sender, GetPersonCompletedEventArgs e)
{
_view.Person= e.Result;
}
}
Nothing happened for me as the Loaded event dont seem to get called, how do i get around this?
Tim Ross has a good introduction to Silverlight MVP implementation, with source code.
I believe the loaded event gets called when the control has been initialized, loaded, rendered and ready for use. This means that as long as you don't place it inside a visible container (so that it is rendered), the loaded event won't be risen.
You may consider using MVC# - a Model View Presenter framework with Silverlight 2.0 support.
Oleg Zhukov

Resources