Prism Library Dialog Service - wpf

The following sample never worked for me:
https://prismlibrary.com/docs/wpf/dialog-service.html
Where the dialogService comming from?
public MainWindowViewModel(IDialogService dialogService)
{
_dialogService = dialogService;
}
How can I add the dialog service?
protected override Window CreateShell()
{
var w = Container.Resolve<MainWindow>();
return w;
}
It's have to go within the RegisterTypes?

Where the dialogService comming from?
From the container. When resolving, the container also resolves all dependencies.
How can I add the dialog service?
You don't have to and normally should shouldn't either. Most of the time, the default implementation provided by the prism framework suffices.
It's have to go within the RegisterTypes?
If you use Unity, every non-concrete type has to be registered to be able to be resolved. That means, prism's dialog service implementation is registered somewhere. Have a look at the code of your application's base class as a starting point.

Related

Extending DialogService in Prism

On the Prism Library website there is a few notes about Simplify your Application Dialog APIs.
https://prismlibrary.com/docs/wpf/dialog-service.html
Let's say I have a Solution with multiple projects, MainProject, Modules.Module1, CoreProject. So creating this DialogServiceExtensions class in my Core project.
public static class DialogServiceExtensions
{
public static void ShowNotification(this IDialogService dialogService, string message, Action<IDialogResult> callBack)
{
dialogService.ShowDialog(nameof(NotificationDialog), new DialogParameters($"message={message}"), callBack, "notificationWindow");
}
}
I also put NotificationDialog and NotificationDialogViewModel in my Core project
I can call it at any project/module, but the question is how can I tell prism that NotificationDialog ViewModel is NotificationDialogViewModel.
Where should I register the dialog, to be able to use thru the hole solution? In my MainProject App.xaml.cs like usual?
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterDialog<NotificationDialog, NotificationDialogViewModel>();
}
Where should I register the dialog, to be able to use thru the hole solution? In my MainProject App.xaml.cs like usual?
If the app wants to show a dialog, you have to do this, as modules are essentially optional (they can be swapped out after deployment or they don't need to exist).
If a module wants to show a dialog (and not the app), you can decide whether it's part of your app's interface to its modules (then put the registration in the app) or not (then put it in the module, each module that uses it, that is, registrations may override each other).

Optional Dependency at Composition Root

I've written a WPF app that has two different main windows. I don't know which one to launch until runtime by looking up what kind of user is using the program in a database. The code I currently have works but Castle Windsor is doing tons of extra work by newing up the object graphs for both kinds of windows.
private readonly IMainWindow _mainWindow;
private readonly ISimplifiedMainWindow _simplifiedMainWindow;
public MainClass(
IMainWindow mainWindow,
ISimplifiedMainWindow simplifiedMainWindow)
{
_mainWindow = mainWindow;
_simplifiedMainWindow = simplifiedMainWindow;
}
public RunApp()
{ // pseudocode
if (user is fullUser) _mainWindow.Show();
else _simplifiedMainWindow.Show();
}
How do I defer creation of my window objects without resorting to making an abstract factory that will basically duplicate what Castle Windsor does anyway?
A factory is in fact the solution I'd recommend (and a solution I've successfully used multiple times in the past to solve this very problem).
I wouldn't implement the factory myself though, let Windsor do it (via a Typed Factory).
public interface IWindowFactory
{
IMainWindow FullUserWindow();
ISimplifiedMainWindow SimplifiedUserWindow();
//optionally
void DestroyWindow(IWindow window);
}
Now you just need to tell Windsor to build a factory for that interface
container.AddFacility<TypedFactoryFacility>();
// later on, in your installer
container.Register(Component.For<IWindowFactory>()
.AsFactory()
.LifestyleTransient());
and your app code changes to:
public RunApp()
{ // pseudocode
if (user is fullUser) Show(factory.FullUserWindow());
else Show(factory.SimplifiedUserWindow());
}

Registering Startup Class In Nancy Using AutoFac Bootstrapper

I've been reading through a lot of the Jabbr code to learn Nancy and trying to implement many of the same patterns in my own application. One of the things I can't seem to get working is the concept of an on application start class. The Jabbr code base has an App_Start folder with a Startup.cs file (here) in it with the following implementation.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
...
SetupNancy(kernel, app);
...
}
}
private static void SetupNancy(IKernel kernel, IAppBuilder app)
{
var bootstrapper = new JabbRNinjectNancyBootstrapper(kernel);
app.UseNancy(bootstrapper);
}
When I tried to do something similar to that in my project the Startup.cs file was just ignored. I searched the Jabbr code base to see if it was used anywhere but I wasn't able to find anything and the only differences I could see is Jabbr uses Ninject while I wanted to use AutoFac
Is there a way to register a startup class in nancy?
Take a look at my project over on GitHub, you'll be interested in the Spike branch and may have to unload the ChainLink.Web project to run I can't remember.
I had some trouble finding a way to configure the ILifetimeScope even after reading the accepted answer here by TheCodeJunkie. Here's how you do the actual configuration:
In the bootstrapper class derived from the AutofacNancyBootstrapper, to actually configure the request container, you update the ILifetimeScope's component registry.
protected override void ConfigureRequestContainer(
ILifetimeScope container, NancyContext context)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>();
builder.Update(container.ComponentRegistry);
}
The application container can be updated similarly in the ConfigureApplicationContainer override.
You should install the Nancy.Bootstrappers.Autofac nuget, inherit from the AutofacNancyBootstrapper type and override the appropriate method (depending on your lifetime scope requirements: application or request). For more info check the readme file https://github.com/nancyfx/nancy.bootstrappers.autofac
HTH
After following the advice from TheCodeJunkie you can use the Update method on the ILifetimeScope container parameter which gives you a ContainerBuilder through an Action:
protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context)
{
container.Update(builder =>
{
builder.RegisterType<MyType>();
});
}

Why Don't DomainService Constructor Overloads Show Up as DomainContext Constructor Overloads?

I wrote an overload for my DomainService class. Problem is, when I recompile, it's not showing up as an overload for my DomainContext. What's wrong? Here is a code sample:
[EnableClientAccess]
public class FoodDomainService : LinqToEntitiesDomainService<FoodEntities>
{
public FoodDomainService(CultureInfo cultureInfo)
{
Thread.CurrentThread.CurrentCulture = cultureInfo;
}
}
And this doesn't work:
FoodDomainContext _foodContext = new FoodDomainContext(Thread.CurrentThread.CurrentCulture);
I get an error that there is no overload matching that. Am I not allowed to do this? Do I need an attribute of some kind?
You are not allowed to do this. When newing up the context from your Silverlight client, you are not directly intantiating your service. Instead, you instantiate a proxy class that was generated by RIA Services, and that proxy class will then call your service. This is why you don't see your constructor: because RIA did not generate it in your proxy.
Doing what you're trying to do would also implicate that there is a round-trip to the server at the time of newing up that FoodDomainContext class, which is not going to happen, because you need to complete the initialisation of that object before you can do so.
Anyway, instead of that you can create a method called SetCurrentCulture() and then call it after initializing the proxy.
This will not work because DomainContext is generated on client code of silverlight, click on view all folders or jump to definition and you will see that code generated will not contain your extra constructor.
Instead you will have to create a method in your domain service and pass information to server.
public SetCultreInfo(int lang,...)
{
.. set culture info
}
On your client, inside constructor you should call,
public MyDomainContext()
{
this.SetCulture(....);
}

Issue intercepting property in Silverlight application

I am using Ninject as DI container in a Silverlight application. Now I am extending the application to support interception and started integrating DynamicProxy2 extension for Ninject. I am trying to intercept call to properties on a ViewModel and ending up getting following exception:
“Attempt to access the method failed: System.Reflection.Emit.DynamicMethod..ctor(System.String, System.Type, System.Type[], System.Reflection.Module, Boolean)”
This exception is thrown when invocation.Proceed() method is called. I tried two implementations of the interceptor and they both fail
public class NotifyPropertyChangedInterceptor: SimpleInterceptor
{
protected override void AfterInvoke(IInvocation invocation)
{
var model = (IAutoNotifyPropertyChanged)invocation.Request.Proxy;
model.OnPropertyChanged(invocation.Request.Method.Name.Substring("set_".Length));
}
}
public class NotifyPropertyChangedInterceptor: IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
var model = (IAutoNotifyPropertyChanged)invocation.Request.Proxy;
model.OnPropertyChanged(invocation.Request.Method.Name.Substring("set_".Length));
}
}
I want to call OnPropertyChanged method on the ViewModel when property value is set.
I am using Attribute based interception.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class NotifyPropertyChangedAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
if(request.Method.Name.StartsWith("set_"))
return request.Context.Kernel.Get<NotifyPropertyChangedInterceptor>();
return null;
}
}
I tested the implementation with a Console Application and it works alright.
I also noted in Console Application as long as I had Ninject.Extensions.Interception.DynamicProxy2.dll in same folder as Ninject.dll I did not have to explicitly load DynamicProxy2Module into the Kernel, where as I had to explicitly load it for Silverlight application as follows:
IKernel kernel = new StandardKernel(new DIModules(), new DynamicProxy2Module());
Could someone please help? Thanks
Reflection can be really tricky in silverlight because of security issues.
Check Gabe's answer for this question, it's the same problem.
The good news is that you can achieve the same functionality you want using dynamic instead of proxies. Just extend your ViewModel from DynamicObject and override the TrySetMember method.
I hope it helps :)

Resources