How set Window's property When A new WPF window Opened - wpf

I want to set new window's property such as showIntaskbar==false in WPF in CefSharp.
I have implemented the interface of ILifeSpanHandler here is my code
public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
{
newBrowser = null;
Window newWindow = (Window)HwndSource.FromHwnd(windowInfo.WindowHandle).RootVisual;
newWindow.ShowInTaskbar = false;
return false;
}
but I get a error ,the windowinfo.WindowHandle's value awalys 0x0000000
please help me.

Related

WinForms Button: draw as the default button without setting the form's AcceptButton property (custom drawing, IsDefault property, BS_DEFPUSHBUTTON)

Imagine the following construction in WinForms .NET. A WinForms form contains a custom control with several buttons, which are instances of the traditional Button class. One of these buttons is the default button for the form. The custom control executes the action associated with the default button when ENTER is pressed. This is done in the redefined ProcessCmdKey method:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Return)
{
buttonOK_Click(null, EventArgs.Empty);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
The default button must have an additional visual cue telling the user that this is the default button (an extra border inside the button). If we did this in a normal form, we would set its AcceptButton property. However, this approach is not applicable here. Even if we find the parent form using the Control.FindForm method or with an expression like (this.Parent as Form), we cannot set the AcceptButton property of the host form and then clear it the right way without resource leak or similar problems (a lot of technical details to place here and to bloat the question).
The first possible way to solve this task is to redefine or enhance the drawing of the button. Is there a relatively easy way to draw a button as the default button with the corresponding visual cue without implementing full custom painting? In my understanding, we might write a special class for our default button based on the following core:
internal class DefaultButton : Button
{
protected override void OnPaint(PaintEventArgs pevent)
{
Rectangle rc = new Rectangle(0, 0, this.Width, this.Height);
ButtonRenderer.DrawButton(pevent.Graphics, rc, System.Windows.Forms.VisualStyles.PushButtonState.Default);
}
}
However, it should take into account the focused state, whether another button on a form is focused (in this case the default button is not drawn with the visual cue), and the like. I could not find a good example of this to use as a basis for my development.
Another possible way to solve my problem could be setting the protected IsDefault property or/and specifying the BS_DEFPUSHBUTTON flag in the overridden CreateParams method in a class inherited from the Button class, for example:
internal class DefaultButton : Button
{
public DefaultButton() : base()
{
IsDefault = true;
}
protected override CreateParams CreateParams
{
get
{
const int BS_DEFPUSHBUTTON = 1;
CreateParams cp = base.CreateParams;
cp.Style |= BS_DEFPUSHBUTTON;
return cp;
}
}
}
But I could not make this code work. Buttons based on this class are always drawn as normal push buttons without the default button visual cue.
I'm not sure about the original requirement; for example I don't have any idea why a UserControl itself should set the AcceptButton of a Form, or what is the expected behavior if there are multiple instances of such controls on the form. It doesn't seem to be responsibility of the UserControl to set the AcceptButton of the Form and there might be better solutions, like relying on events and setting the AcceptButton.
Anyways, the following code example shows you how to set the AcceptButton of a Form; maybe it helps you to find a solutions. The highlights of the code:
The code uses dispose to set the AcceptButton to null.
The code implements ISupportInitialize to set the accept button after initialization of the control is done. If you create the control instance at run-time with code, don't forget to call EndInit, like this: ((System.ComponentModel.ISupportInitialize)(userControl11)).EndInit(); after adding it to the Form, but if you use designer, the designer will take care of that.
The code calls NotifyDefault(true) just for visual effect in design time when it's hosted on a form.
Here's the example:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public class UserControl1 : UserControl, ISupportInitialize
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(15, 57);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(96, 57);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 1;
this.button2.Text = "button2";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(15, 17);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
this.textBox1.TabIndex = 2;
//
// UserControl1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "UserControl1";
this.Size = new System.Drawing.Size(236, 106);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBox1;
public System.Windows.Forms.Button button1;
public System.Windows.Forms.Button button2;
public UserControl1()
{
InitializeComponent();
//Just for visual effect in design time when it's hosted on a form
button2.NotifyDefault(true);
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("1");
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("2");
}
public void BeginInit()
{
}
public void EndInit()
{
var f = this.FindForm();
if (f != null)
f.AcceptButton = button2;
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
if (disposing)
{
var f = this.FindForm();
if (f != null)
f.AcceptButton = null;
}
base.Dispose(disposing);
}
}
}

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);
}

Devexpress PopupContainerEdit popup always open

Im'm using winform DevExpress library.
Now need to create a control, basing on PopupContainerEdit but this control must have some behaviors like when it's focused, the popup opens and when lost focus the popup closes.
This is the code I'm using but the popup dessapears after getting focus.
public class HelpEdit : PopupContainerEdit {
private PopupContainerControl _container;
private GridControl _gridControl;
private GridView _gridView;
[DefaultValue("")]
[DXCategory("Data")]
[AttributeProvider(typeof(IListSource))]
public object Datasource {
get { return _gridControl.DataSource; }
set { _gridControl.DataSource = value; }
}
public HelpEdit() : base() {
_container = new PopupContainerControl();
this.Properties.TextEditStyle = DevExpress.XtraEditors.Controls.TextEditStyles.Standard;
this._gridControl = new GridControl();
this._gridControl.Dock = DockStyle.Fill;
this._gridView = new GridView(_gridControl);
_container.Controls.Add(_gridControl);
_container.Size = new Size(this.Width, 250);
this.Properties.PopupControl = _container;
this.Properties.PopupControl.Size = new Size(this.Width, 250);
}
protected override void OnGotFocus(EventArgs e) {
base.OnGotFocus(e);
this.ShowPopup();
}
protected override void OnLostFocus(EventArgs e) {
base.OnLostFocus(e);
this.ClosePopup();
}
}
Your popup disappears because it closes by your code as soon as the popup container control(_container) got focus itself. You should not close popup within the OnLostFocus() override because the base.OnLostFocus method of PopupContainerEdit is already contains correct code for closing popup. Or close popup conditionally, using the following code:
protected override void OnLostFocus(EventArgs e) {
if(IsPopupOpen && !EditorContainsFocus)
ClosePopup(PopupCloseMode.Immediate);
base.OnLostFocus(e);
}

Read Control Value from backgroundworker thread in WPF

I'm trying to read the values of the controls from a backgroundworker.
There are plenty of examples of how to update a control from a background thread, but i've not been able to find one example of how to read from it.
At the moment I have created a struct to pass to the backgroundworker, but it does not seem very elegant.
Struct:
public struct Arguments
{
public string version;
public bool isChecked;
public Arguments(string Version, bool IsChecked)
{
version = Version;
isChecked = IsChecked;
}
}
Button Click Event
Arguments pass = new Arguments(Version.Text.Trim(), (bool)Credentials.IsChecked);
export.RunWorkerAsync(pass);
DoWork Event
ExportSolution export = new ExportSolution(this, messageBox);
Arguments pass = (Arguments)e.Argument;
export.Export(pass.version, pass.isChecked);
This works fine, but I would like to do the following or something similar
DoWork event
ExportSolution export = new ExportSolution(this, messageBox);
export.Export(Access Version.Text.Trim() from here, ditto (bool)Credentials.IsChecked);
TIA
This is what I've ended up doing:
string version;
bool isChecked;
public MainWindow()
{
InitializeComponent();
this.DataContext = validator;
//export.DoWork +=new DoWorkEventHandler(export_DoWork);
export.DoWork += (sender, args) =>
{
ExportSolution exports = new ExportSolution(this, messageBox);
Dispatcher.Invoke((Action)(() => version = Version.Text.Trim()));
Dispatcher.Invoke((Action)(() => isChecked = (bool)Credentials.IsChecked));
exports.Export(version, isChecked);
};
}
Where Version is a textbox and Credentials is a Checkbox.
If you are working on Code Behind, you can do the DoWork event as a Lambda expression,
eg.
DoWork+=(_,_)=>{...}
then inside the labda expression you can see the outside scope, and you can see the windows control's names, and the buttob.

Winforms DataBind to Control's Visible Property

Are there any known issues when databinding to a control's visible property?
The control is always NOT visible regardless of what my property is.
Public ReadOnly Property IsRibbonCategory() As Boolean
Get
Return True
End Get
End Property
I tried the control's text property and other properties and they seem to work correctly.
I am trying to set a Panel's visible property.
I've found that life is better if you assume that binding to a control's Visible property is broken, despite the fact that it sometimes works. See http://support.microsoft.com/kb/327305, which says as much (and while the KB article applies to .NET 1.0 and 1.1, it still seems to be a problem in at least 2.0).
I created a utility class for creating bindings which, among other things, gave me a centralized place to add a work-around. Instead of actually creating a binding on Visible it does two things:
It subscribes to the data source's INotifyPropertyChanged.PropertyChanged event and sets the Visible value as appropriate when the event is raised.
It sets the initial value of Visible according to the current data source value.
This required a little reflection code, but wasn't too bad. It is critical that you don't bind the Visible property and do the work-around or it won't work.
Workaround: Set the Visible property on the BindingComplete event.
I had same issue setting a label's Visible property - always stays false, even though setting the Enabled property works fine.
I just hit this issue in .NET 4.7.1 and Visual Studio 2017. To fix it, I changed the Visible property on my control to be initially set to True, as I had it as False previously.
Things to check:
Be sure you've instantiated the class that has the IsRibbonCategory property
Did you set the datasource of property of the binding source to the instance of the class
The datasource update mode should be on "on validation"
Make sure you didn't set the visible property manually to false on the control
Hope that helps. Can you post more code?
A workaround would be to use a Component to databind to a control's visiblity property instead of directly binding to the control's visibility property.
See below code:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public class ControlVisibilityBinding : Component
{
private static readonly object EventControlChanged = new object();
private static readonly object EventVisibleChanged = new object();
private System.Windows.Forms.Control _control;
private bool _visible = true;
public event EventHandler VisibleChanged
{
add { Events.AddHandler(EventVisibleChanged, value); }
remove { Events.RemoveHandler(EventVisibleChanged, value); }
}
public event EventHandler ControlChanged
{
add { Events.AddHandler(EventControlChanged, value); }
remove { Events.RemoveHandler(EventControlChanged, value); }
}
public ControlVisibilityBinding()
{
}
public ControlVisibilityBinding(IContainer container)
{
container.Add(this);
}
[DefaultValue(null)]
public System.Windows.Forms.Control Control
{
get { return _control; }
set
{
if(_control == value)
{
return;
}
WireControl(_control, false);
_control = value;
if(_control != null)
{
_control.Visible = _visible;
}
WireControl(_control, true);
OnControlChanged(EventArgs.Empty);
OnVisibleChanged(EventArgs.Empty);
}
}
[DefaultValue(true)]
public bool Visible
{
get { return _visible; }
set
{
if(_visible != value)
{
_visible = value;
}
if(Control != null)
{
Control.Visible = _visible;
}
OnVisibleChanged(EventArgs.Empty);
}
}
private void WireControl(Control control, bool subscribe)
{
if(control == null)
{
return;
}
if(subscribe)
{
control.VisibleChanged += Control_VisibleChanged;
}
else
{
control.VisibleChanged -= Control_VisibleChanged;
}
}
private void Control_VisibleChanged(object sender, EventArgs e)
{
OnVisibleChanged(EventArgs.Empty);
}
protected virtual void OnVisibleChanged(EventArgs e)
{
EventHandler subscribers = (EventHandler)Events[EventVisibleChanged];
if(subscribers != null)
{
subscribers(this, e);
}
}
protected virtual void OnControlChanged(EventArgs e)
{
EventHandler subscribers = (EventHandler)Events[EventControlChanged];
if(subscribers != null)
{
subscribers(this, e);
}
}
}
static class Program
{
[STAThread]
static void Main()
{
using(Form form = new Form())
using(FlowLayoutPanel groupBoxLayoutPanel = new FlowLayoutPanel())
using(RadioButton visibleButton = new RadioButton())
using(RadioButton hiddenButton = new RadioButton())
using(GroupBox groupBox = new GroupBox())
using(Label text = new Label())
using(ControlVisibilityBinding visibilityBinding = new ControlVisibilityBinding())
using(TextBox inputTextBox = new TextBox())
{
groupBoxLayoutPanel.Dock = DockStyle.Fill;
groupBoxLayoutPanel.FlowDirection = FlowDirection.LeftToRight;
groupBoxLayoutPanel.AutoSize = true;
groupBoxLayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
visibleButton.Text = "Show Label";
visibleButton.AutoSize = true;
hiddenButton.Text = "Hide Label";
hiddenButton.AutoSize = true;
groupBoxLayoutPanel.Controls.Add(visibleButton);
groupBoxLayoutPanel.Controls.Add(hiddenButton);
inputTextBox.Text = "Enter Label Text Here";
inputTextBox.Dock = DockStyle.Top;
groupBox.AutoSize = true;
groupBox.AutoSizeMode = AutoSizeMode.GrowAndShrink;
groupBox.Controls.Add(groupBoxLayoutPanel);
groupBox.Dock = DockStyle.Fill;
text.AutoSize = true;
text.ForeColor = Color.Red;
text.Dock = DockStyle.Bottom;
text.BorderStyle = BorderStyle.FixedSingle;
text.Font = new Font(text.Font.FontFamily, text.Font.Size * 1.25f, FontStyle.Bold | FontStyle.Italic);
text.DataBindings.Add("Text", inputTextBox, "Text", true, DataSourceUpdateMode.Never);
visibilityBinding.Control = text;
visibleButton.DataBindings.Add("Checked", visibilityBinding, "Visible", true, DataSourceUpdateMode.OnPropertyChanged);
Binding binding = hiddenButton.DataBindings.Add("Checked", visibilityBinding, "Visible", true, DataSourceUpdateMode.OnPropertyChanged);
ConvertEventHandler invertConverter = (sender, e) => e.Value = !((bool)e.Value);
binding.Format += invertConverter;
binding.Parse += invertConverter;
form.Controls.Add(inputTextBox);
form.Controls.Add(text);
form.Controls.Add(groupBox);
Application.Run(form);
}
}
}
}
Here is my turn around, it may be stupid but it worked many times.
I put one Panel control in my form, I make it to Fill my form and I put everything in that Panel. All the controls I bind the Visible property see their visibility change according to the objects in my DataGridView.

Resources