Button is always disabled using CompositeCommand in Prism5 with WPF - wpf

Hi I wrote code for view navigation, For that i added button on my navigation area on that button click i want to open view in content area My code is
ModuleCode
public class ClientModule : ModuleBase
{
public ClientModule(IUnityContainer container, IRegionManager regionManager)
: base(container, regionManager) { }
protected override void InitializeModule()
{
RegionManager.RegisterViewWithRegion("NavigationRegion", typeof(Navigation));
RegionManager.RegisterViewWithRegion("ContentRegion", typeof(Content));
}
protected override void RegisterTypes()
{
Container.RegisterType<object, Navigation>(typeof(Navigation).FullName);
Container.RegisterType<object,Content>(typeof(Content).FullName);
}
}
}
Bootstrap is
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return this.Container.Resolve<Shell>();
}
protected override void InitializeShell()
{
base.InitializeShell();
App.Current.MainWindow = (Window)this.Shell;
App.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType<IShellViewModel, ShellViewModel>();
}
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();
mappings.RegisterMapping(typeof(StackPanel), Container.Resolve<StackPanelRegionAdapter>());
return mappings;
}
protected override void ConfigureModuleCatalog()
{
base.ConfigureModuleCatalog();
ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
moduleCatalog.AddModule(typeof(ClientModule));
}
}
and my navigationview have 1 button as below
<StackPanel>
<Button Command="{x:Static infCommands:ApplicationCommands.NavigateCommand}"
CommandParameter="{x:Type views:Content}"
Name="btnTest">Navigate to Content</Button>
</StackPanel>
now problem is when i run my application button always show disable, Can any one tell me what is the problem and what is its solution.
Thanks

I got this working.
I was using same code following a pluralsight video about Prism.
Issue was that the only commmand associated with CompositeCommand was not set to Active. After setting IsActive to true, CompositeCommand became active, and button was enabled.
Following is from msdn docs for Prism
The CompositeCommand can be configured to evaluate the active status of child DelegateCommands (in addition to the CanExecute status) by specifying true for the monitorCommandActivity parameter in the constructor. When this parameter is set to true, the CompositeCommand class will consider each child DelegateCommand's active status when determining the return value for the CanExecute method and when executing child commands within the Execute method.
When the monitorCommandActivity parameter is true, the CompositeCommand class exhibits the following behavior:
CanExecute. Returns true only when all active commands can be executed. Child commands that are inactive will not be considered at all.
Execute. Executes all active commands. Child commands that are inactive will not be considered at all.

Related

Winforms WebBrowser control without IE popups not appearing [duplicate]

I am trying to implement a simple web browser control in one of my apps. This is to help integrate a web app into a toolset i am creating.
The problem is, this web app absolutly loves popup windows....
When a popup is opened, it opens in an IE window which is not a child of the MDI Container form that my main window is part of.
How can i get any and all popups created by clicking links in my WebBrowser to be a child of my MDI container (similar to setting the MDIParent property of a form)?
Thanks in advance.
The web browser control supports the NewWindow event to get notified about a popup window. The Winforms wrapper however does not let you do much with it, you can only cancel the popup. The native COM wrapper permits passing back a new instance of the web browser, that instance will then be used to display the popup.
Taking advantage of this requires some work. For starters, use Project + Add Reference, Browse tab and select c:\windows\system32\shdocvw.dll. That adds a reference to the native COM interface.
Create a form that acts as the popup form. Drop a WebBrowser on it and make its code look similar to this:
public partial class Form2 : Form {
public Form2() {
InitializeComponent();
}
public WebBrowser Browser {
get { return webBrowser1; }
}
}
The Browser property gives access to the browser that will be used to display the web page in the popup window.
Now back to the main form. Drop a WebBrowser on it and make its code look like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
webBrowser1.Url = new Uri("http://google.com");
}
SHDocVw.WebBrowser nativeBrowser;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
nativeBrowser = (SHDocVw.WebBrowser)webBrowser1.ActiveXInstance;
nativeBrowser.NewWindow2 += nativeBrowser_NewWindow2;
}
protected override void OnFormClosing(FormClosingEventArgs e) {
nativeBrowser.NewWindow2 -= nativeBrowser_NewWindow2;
base.OnFormClosing(e);
}
void nativeBrowser_NewWindow2(ref object ppDisp, ref bool Cancel) {
var popup = new Form2();
popup.Show(this);
ppDisp = popup.Browser.ActiveXInstance;
}
}
The OnLoad method obtains a reference to the native COM interface, then subscribes an event handler to the NewWindow2 event. I made sure to unsubscribe that event in the FormClosing event handler, not 100% sure if that's necessary. Better safe then sorry.
The NewWindow2 event handler is the crux, note that the first argument allows passing back an untyped reference. That should be the native browser in the popup window. So I create an instance of Form2 and Show() it. Note the argument to Show(), that ensures that the popup is an owned window. Substitute this as necessary for your app, I assume you'd want to create an MDI child window in your case.
Do beware that this event doesn't fire for the window displayed when Javascript uses alert(). The browser doesn't treat that window as an HTML popup and doesn't use a browser window to display it so you cannot intercept or replace it.
I found that the best way to do this was to implement/sink the NewWindow3 event
Add the reference to c:\windows\system32\shdocvw.dll as mentioned in the other answers here.
Add event handler
SHDocVw.WebBrowser wbCOMmain = (SHDocVw.WebBrowser)webbrowser.ActiveXInstance;
wbCOMmain.NewWindow3 += wbCOMmain_NewWindow3;
Event method
void wbCOMmain_NewWindow3(ref object ppDisp,
ref bool Cancel,
uint dwFlags,
string bstrUrlContext,
string bstrUrl)
{
// bstrUrl is the url being navigated to
Cancel = true; // stop the navigation
// Do whatever else you want to do with that URL
// open in the same browser or new browser, etc.
}
Set "Embed Interop Types" for the "Interop.SHDocVw" assembly to false
Set the "local copy" to true.
Source for that help MSDN Post
Refining Hans answer, you can derive the WebBrowser for accessing the COM without adding the reference. It is by using the unpublished Winforms WebBrowser.AttachInterface and DetachInterface methods.
More elaborated here.
Here is the code:
Usage (change your WebBrowser instance to WebBrowserNewWindow2)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.webBrowser1.NewWindow2 += webBrowser_NewWindow2;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
webBrowser1.NewWindow2 -= webBrowser_NewWindow2;
base.OnFormClosing(e);
}
void webBrowser_NewWindow2(object sender, WebBrowserNewWindow2EventArgs e)
{
var popup = new Form1();
popup.Show(this);
e.PpDisp = popup.Browser.ActiveXInstance;
}
public WebBrowserNewWindow2 Browser
{
get { return webBrowser1; }
}
}
Code:
using System;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace SHDocVw
{
public delegate void WebBrowserNewWindow2EventHandler(object sender, WebBrowserNewWindow2EventArgs e);
public class WebBrowserNewWindow2EventArgs : EventArgs
{
public WebBrowserNewWindow2EventArgs(object ppDisp, bool cancel)
{
PpDisp = ppDisp;
Cancel = cancel;
}
public object PpDisp { get; set; }
public bool Cancel { get; set; }
}
public class WebBrowserNewWindow2 : WebBrowser
{
private AxHost.ConnectionPointCookie _cookie;
private WebBrowser2EventHelper _helper;
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void CreateSink()
{
base.CreateSink();
_helper = new WebBrowser2EventHelper(this);
_cookie = new AxHost.ConnectionPointCookie(
this.ActiveXInstance, _helper, typeof(DWebBrowserEvents2));
}
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void DetachSink()
{
if (_cookie != null)
{
_cookie.Disconnect();
_cookie = null;
}
base.DetachSink();
}
public event WebBrowserNewWindow2EventHandler NewWindow2;
private class WebBrowser2EventHelper : StandardOleMarshalObject, DWebBrowserEvents2
{
private readonly WebBrowserNewWindow2 _parent;
public WebBrowser2EventHelper(WebBrowserNewWindow2 parent)
{
_parent = parent;
}
public void NewWindow2(ref object pDisp, ref bool cancel)
{
WebBrowserNewWindow2EventArgs arg = new WebBrowserNewWindow2EventArgs(pDisp, cancel);
_parent.NewWindow2(this, arg);
if (pDisp != arg.PpDisp)
pDisp = arg.PpDisp;
if (cancel != arg.Cancel)
cancel = arg.Cancel;
}
}
[ComImport, Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
TypeLibType(TypeLibTypeFlags.FHidden)]
public interface DWebBrowserEvents2
{
[DispId(0xfb)]
void NewWindow2(
[In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp,
[In, Out] ref bool cancel);
}
}
}
I know the question is very old but I solved it this way: add new reference, in COM choose Microsoft Internet Controls and in the code, before the click that opens a new window add the following:
SHDocVw.WebBrowser_V1 axBrowser = (SHDocVw.WebBrowser_V1)webBrowser1.ActiveXInstance;
axBrowser.NewWindow += axBrowser_NewWindow;
and then add the following method:
void axBrowser_NewWindow(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Processed)
{
Processed = true;
webBrowser1.Navigate(URL);
}

RequestNavigate in MainWindowViewModel ctor

hi i want when application luanched, application navigate to a view automatically so i used like this:
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<MainContent>();
containerRegistry.RegisterForNavigation<Subscene>();
}
and in MainWindowViewModel
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
_regionManager.RequestNavigate("ContentRegion", "Subscene", myparameter);
}
this code not work, No errors and no navigation
my region exist in another usercontrol called MainContent
This works for "normal" view models only, not for the view model of the shell, because that one is created too early. You should do the initial navigation in OnInitialized.
internal class MyApp : PrismApplication
{
// ...
protected override void OnInitialized()
{
base.OnInitialized();
Container.Resolve<IRegionManager>().RequestNavigate("ContentRegion", "Subscene", myparameter);
}
// ...
}
Unrelated sidenote: if you use the parameter instead of the field in the constructor, Resharper will tell you when the field is no longer needed in future refactorings.

How to show login screen before shell in prism 7 ? Because there is PrismApplication in app.xaml and no OnStartup() method in app.xaml.cs

I want to show login screen before shell in my prism application (prism 7) so i don't know how to do it because there is no OnStartup() method in app.xaml.cs class file where I show the login window before bootstrapper loads.
Previously in prism 5 for login I open a login window before bootstrapper. If credentials are correct then bootstrapper loads.
Please help me out.
// app.xaml.cs file
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<Shell>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
//return new DirectoryModuleCatalog() { ModulePath = Environment.CurrentDirectory };
}
}
there is no OnStartup() method
Says who?
Just write
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartUp(e);
}
within your app.xaml.cs and add whatever functionality you require.
PrismApplication in Prism 7 is a child of PrismApplicationBase which has
protected override void OnStartup(StartupEventArgs e);
So, as stated by Haukinger, overriding this method and inserting your login code should work.

Unity activation error occured while trying to get instance of type

I am using Prism 4 with Unity Extensions and the MVVM pattern.
public class Bootstrapper : UnityBootstrapper {
protected override void InitializeShell() {
Application.Current.RootVisual = (UIElement) Shell;
}
protected override DependencyObject CreateShell()
{
return ServiceLocator.Current.GetInstance<Shell>();
}
}
ServiceLocator.Current.GetInstance() throws the following exception :
Activation error occured while trying to get instance of type Shell,
key ""
You probably have an error in the shell constructor.
If you have parameters in Shell constructor for exemple, dont forget to declare in ConfigureContainer of Bootstrapper :
Bootstrapper.cs
...
protected override void ConfigureContainer()
{
base.ConfigureContainer();
this.Container.RegisterType<IMyService, MyService>(new ContainerControlledLifetimeManager());
}
Shell.cs
...
public Shell(IMyService container)
{
...
}
You can read this doc : http://msdn.microsoft.com/en-us/library/gg430868(v=pandp.40).aspx
I have two seperate suggestions:
1)ensure that the name property of shell.xaml is not empty
2)If 1 does not help change the InitializeShell like this:
IShellView shell = new Shell();
shell.ShowView();
return shell as DependencyObject;
I hope these could help.

Composite Commands Not Working

I am working on a Composite MVVM application and trying to get Global Binding events happening - Except it is NOT!..
the buttons are disabled by default although the CanRun returns true!! !! I have followed the Composite Guide and the OnLoadMenu is not firing!!!
I have been going around in circles (Event Aggregators, DelegateCommands, Composite Commands) It just isnt working. Can any please look at this and tell me what I am Missing??
//xmlns:local="clr-namespace:Commands;assembly=MyApp"
<Button HorizontalAlignment="Center" Margin="1,1,1,1"
Grid.Row="2"
Command="{x:Static local:AdminGlobalCommands.LoadAdminMenu}"/>
public static class AdminGlobalCommands // In Common Code Library
{
//List All Global Commands Here
public static CompositeCommand LoadAdminMenu = new CompositeCommand();
}
public class AdminModuleViewModel : ViewModelBase, IAdminModuleViewModel // In AdminModule
{
protected IRegionManager _regionManager;
private IUnityContainer _container;
public AdminModuleViewModel(
IEventAggregator eventAggregator,
IBusyService busyService,
IUnityContainer container,
IRegionManager regionManager
)
: base(eventAggregator, busyService, container)
{
// show the progress indicator
busyService.ShowBusy();
this._regionManager = regionManager;
this._container = container;
//set up the command receivers
this.AdminShowMenuCommand = new DelegateCommand<object>(this.OnLoadAdminMenu, this.CanShowAdminMenu);
//Listen To Events
AdminGlobalCommands.LoadAdminMenu.RegisterCommand(AdminShowMenuCommand);
busyService.HideBusy();
}
public DelegateCommand<object> AdminShowMenuCommand { get; private set; }
private bool CanShowAdminMenu(object obj)
{ //Rules to Handle the Truth
return true;
}
public void OnLoadAdminMenu(object obj)
{
UIElement viewToOpen = (UIElement)_container.Resolve(typeof(AdminMenuControl)) ;
_regionManager.AddToRegion("MainRegion", viewToOpen);
_regionManager.Regions["MainRegion"].Activate(viewToOpen); ;
}
}
When using PRISM if you are creating a CompositeCommand with monitorCommandActivity set to true, you also need to be aware of and set DelegateCommand.IsActive state.
In that case CompositeCommand will not consider inactive DelegateCommands and as a result your button might stay disabled (for example when no other active and executable DelegateCommand is in the CompositeCommands's command chain).

Resources