Unity and IServiceProvider on Prism for WPF - wpf

I have a WPF Prism application with Unity container.
I would like to add the Serilog logging service.
So I override RegisterTypes as follows:
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterServices(serviceCollection =>
serviceCollection.AddLogging(logbuilder => logbuilder.AddSerilog(dispose: true)));
}
I have following Nuget packages installed:
Prism.Core
Prism.Unity
Prism.Unity.Extensions
Prism.Wpf
When resolving het MainWindow type from the container I get the error InvalidOperationException: No public constructor is available for type System.IServiceProvider
Related information:
working solution for Prism Xamarin Forms and Dryloc or Unity: DryIoc and IServiceProvider on Prism for Xamarin.Forms (DryIoc.Microsoft.DependencyInjection)
https://github.com/augustoproiete/prism-logging-serilog/issues/3
.net5.0 PRISM WPF application, how to use Microsoft.Exensions.Logging with Serilog as provider?
I can get it to work when I follow the implementation documented in https://www.andicode.com/prism/wpf/logging/2021/05/21/Logging-In-Prism.html
but this is not the same methodology as for Prism Xamarin Forms and Dryloc or Unity.
What is the reason for the difference between WPF and Xamarin Forms?

Related

Can a WPF Application be hosted on a thread separate from the UI thread?

I'm working on a project to integrate WPF Windows into a large application written in Visual FoxPro. The project has been progressing for a couple of years with success.
One downside to this project is the limitation of the UI thread. FoxPro is an STA app, so there is only one thread that both UI and application services must share. While the application is retrieving data, the UI is locked up. It is my hope that the method we're using to integrate WPF into this app gives us an opportunity to introduce a separate UI thread for the WPF Windows we're using.
How do we integrate WPF into a STA app?
We build a .NET COM server, not an ActiveX control. Instead we're using a simple COM control that exposes events. Our FoxPro client app subscribes to the events and handles UI requests through these events.
We start with a couple of .NET classes that the COM server will use.
// This class allows us to initialize an Application within a COM server
// since there is no App.xaml to do that for us.
[ComVisible(false)]
public class MyApp : System.Windows.Application
{ }
// This class allows us to assign the FoxPro app's main window as the owner
[ComVisible(false)]
public abstract class MyWindow : System.Windows.Window
{
private System.Windows.Interop.WindowInteropHelper _helper;
public void AssignOwner(int hWnd)
{
_helper = new WindowInteropHelper(this);
_helper.Owner = new IntPtr(hWnd);
}
}
The FoxPro app instantiates an instance of the COM server, subscribes to COM events, then calls a method to show the WPF window. The COM server's Show method first causes this bit of code to execute once per VFP app by delegating it to a static class.
if (Application.Current == null)
_ = new MyApp();
if (Application.Current != null)
{
Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
Application.Current.DispatcherUnhandledException += Application_DispatcherUnhandledException;
}
The Show method then builds a Window and displays it. There's nothing special here.
// Build a business model to access data and services through COM events
var model = new MyModel(this);
// ShellView is an implementation of MyWindow
var window = new ShellView { DataContext = new ShellViewModel(model) };
if (hWnd > 0)
window.AssignOwner(hWnd); && hWnd is a handle to the FoxPro window
window.Show();
The Question
Does the static code that builds the WPF Application instance give us the opportunity to construct a separate UI thread for the Dispatcher used by the WPF components?

WPF WebBrowser custom right click menu stopped working after migrating the app to .NET Core 3.1

I've got a WPF application that uses the WebBrowser control as an HTML viewer. I didn't want it to have the default right click context menu so I've found this piece of code to display my custom one instead.
private void TheBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
documentEvents = TheBrowser.Document as HTMLDocumentEvents2_Event;
if (documentEvents != null)
{
documentEvents.oncontextmenu += webBrowserChat_ContextMenuOpening;
}
}
private bool webBrowserChat_ContextMenuOpening(IHTMLEventObj pEvtObj)
{
return false;
}
That has worked just fine until I've migrated the app from .NET Framework 4.7 to .NET Core 3.1.
Now it throws this exception:
System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'
Inner exception
TypeLoadException: Could not load type 'System.Runtime.InteropServices.UCOMIConnectionPointContainer' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
None the ways to disable the context menu I found works in .NET Core WPF. I don't really need to have my custom menu, just disabling it altogether would do.
If there's a "new" way to do it in .NET Core 3.1 please tell me. Thanks.

Integrate an MVVM WPF Solution with Caliburn Micro and MEF into an old WPF Applicaion with codbehind and Page Navigation

Last year I built a WPF application using page navigation and no MVVM.
Recently I was asked to build a new application for the same customer which I did in WPF MVVM with Caliburn Micro and MEF. Now my customer asks me to integrate the new application into the old one.
My thought was to add a new page to the old application and to integrate the shell of the new application into a ContentControl of this page.
My problem now is that the old application is started by an
<StartupUri="Views\NavWindow.xaml">
entry in the app.xaml, while the new application is started by a bootstrapper like
<local:AppBootstrapper x:Key="bootstrapper" />
where AppBootstrapper looks like
class AppBootstrapper : Bootstrapper<ShellViewModel>
{
private CompositionContainer container;
protected override void Configure()
{
container = new CompositionContainer(new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
CompositionBatch batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container);
container.Compose(batch);
}
protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = container.GetExportedValues<object>(contract);
if (exports.Count() > 0)
{
return exports.First();
}
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
}
So, as far as I understand, in case of the new app the bootstrapper initializes the whole app, calls the ShellViewModel and eventually the ShellView.
Because I use the EventAggregator in the new app to send messages from one viewmodel to another, I think I canĀ“t just get rid of the bootstrapper and use the view-first model of Caliburn Micro.
So my problem is: can I call the bootstrapper from my old app by myself, and if so, where should I store the instance of it, and how do I tell Caliburn Micro where to put the ShellView?
Any help is appreciated.
CM is so light that in these situations it's actually worth having a peek at the source to see what a particular class is actually doing.
The Bootstrapper works because declaring it in the resources file of the application forces an instantiation of it. The constructor calls Start on the instance and that sets up the aggregator, IOC, etc.
https://caliburnmicro.codeplex.com/SourceControl/changeset/view/4de6f2a26b21#src/Caliburn.Micro.Silverlight/Bootstrapper.cs
If you were to load the application into a ContentControl in another application, I can't see a reason why it wouldn't kick off CM as the resources for the loaded application would still be processed, instantiating and starting up the Bootstrapper etc. Have you tried it in a test project? That might be your first option.
There may be some areas where CMs default implementation of Bootstrapper might not be ideal, but on first glance I can't see any glaring issues (not sure what happens to the application events such as OnStartup etc when you load a sub-application so you might want to look at that). Worst case you can roll your own Bootstrapper for the sub-app and just rebuild with the tweaked functionality.

silverlight dataform control unavailable

I have RIA services installed and also have silverlight 3.0 but there is no system.windows.controls.data.dataform . On account of this, I am unable to use dataform control . WHat should I do?I have also tried to download the same but unable to find it.
DataForm is not currently in the SDK. Its found in the Toolkit. Download and install the Nov09 Silverlight Toolkit for Silverlight 3.
You need to add the System.Windows.Controls.Data.DataForm.Toolkit reference to your project. Then the DataForm will be available in the System.Windows.Controls namespace.

How to access application object in Silverlight class library?

Suppose my solution have two project:
myApp: silverlight application project: the default application App
MyLib: silverlight class library project
then in code for those controls in Mylib, how to access the application object App?
Application.Current should do you right, box as necessary((MyAppClass)Application.Current).something

Resources