I have used the code from this blog, as below but abridged, and I see the WinForm inside my main window, but the sample text I placed on it in a label is not visible.
[System.Windows.Markup.ContentProperty("Child")]
public class WinFormsHost : HwndHost
{
public WinFormsHost()
{
var form = new ChildForm();
Child = form;
}
private System.Windows.Forms.Form child;
public event EventHandler<ChildChangedEventArgs> ChildChanged;
public System.Windows.Forms.Form Child
{
get { return child; }
set
{
HwndSource ps = PresentationSource.FromVisual(this) as HwndSource;
if (ps != null && ps.Handle != IntPtr.Zero)
{
throw new InvalidOperationException("Cannot set the Child property after the layout is done.");
}
Form oldChild = child;
child = value;
OnChildChanged(oldChild);
}
}
private void CheckChildValidity()
{
if (child == null || child.Handle == IntPtr.Zero)
{
throw new ArgumentNullException("child form cannot be null");
}
}
public Boolean ShowCaption
{
get
{
CheckChildValidity();
return (GetWindowStyle(Child.Handle) & WindowStyles.WS_BORDER) == WindowStyles.WS_CAPTION;
}
set
{
if (child == null)
{
this.ChildChanged += delegate
{
if (value)
{
SetWindowStyle(Child.Handle, GetWindowStyle(Child.Handle) | WindowStyles.WS_CAPTION);
}
else
{
SetWindowStyle(Child.Handle, GetWindowStyle(Child.Handle) & ~WindowStyles.WS_CAPTION);
}
};
}
else
{
if (value)
{
SetWindowStyle(Child.Handle, GetWindowStyle(Child.Handle) | WindowStyles.WS_CAPTION);
}
else
{
SetWindowStyle(Child.Handle, GetWindowStyle(Child.Handle) & ~WindowStyles.WS_CAPTION);
}
}
}
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
CheckChildValidity();
HandleRef childHwnd = new HandleRef(Child, child.Handle);
SetWindowStyle(childHwnd.Handle, WindowStyles.WS_CHILD | GetWindowStyle(childHwnd.Handle));
WindowsFormsHost.EnableWindowsFormsInterop();
System.Windows.Forms.Application.EnableVisualStyles();
SetParent(childHwnd.Handle, hwndParent.Handle);
return childHwnd;
}
}
And:
<Window x:Class="WinFormsHost"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:cc="clr-namespace:XTime.Shell.WinformsHost"
Title="Hosting Form In WPF">
<cc:WinFormsHost ShowCaption="False">
<wf:Form/>
</cc:WinFormsHost>
</Window>
<cc:WinFormsHost ShowCaption="False">
<wf:Form/>
</cc:WinFormsHost>
Your XAML embeds a System.Windows.Forms.Form object inside the WinFormsHost. Which is what you got, just a blank form with no child controls embedded inside it. It looks like you made an attempt at creating your own in the WinFormsHost constructor, assigning the Child property, but your XAML is overriding it so you are just left with a blank form again.
I put a ChildForm class inside the same namespace:
using System.Windows.Forms;
using System.Drawing;
...
public class ChildForm : System.Windows.Forms.Form {
public ChildForm() {
this.BackColor = Color.FromKnownColor(KnownColor.Window);
var lbl = new Label { Text = "Hello world" };
this.Controls.Add(lbl);
}
}
And updated the XAML to:
<cc:WinFormsHost ShowCaption="False">
<cc:ChildForm/>
</cc:WinFormsHost>
To get:
Set the FormBorderStyle to None to get rid of the border. Etcetera.
Setting the form's TopLevel property to false and Visible property to true is the much simpler way to turn a Form into a child control btw. I left it this way since you hinted you might want to give a Delphi window the same treatment. In which case you might want to go back to your original approach again, creating the child in the form class constructor and just omitting the content assignment in the XAML.
Related
I put a DataGridView in a UserControl and create a public property in my usercontrol that exposes datagridview's columns property.Here is the sample code:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public DataGridViewColumnCollection MyDataGridColumns
{
get
{
return dataGridView1.Columns;
}
}
}
Then I add UserControl1 in my form and I click on MyDataGridColumns property in property window and add 1 or more columns. The problem happens when I rebuild my solution; All of the columns that I have just added disappear after rebuilding.
Can anyone explain to me why this happens? and how to solve it?
This works for me : I created a specific columns editor as it seems it is impossible to use the default columns editor for any control that does not extend DataGridView.
public partial class UserControl1 : UserControl, IDataGridView
{
public UserControl1()
{
InitializeComponent();
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
public DataGridView DataGridView
{
get { return dataGridView1; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor(typeof(ExtendedDataGridViewColumnCollectionEditor), typeof(UITypeEditor))]
[MergableProperty(false)]
public DataGridViewColumnCollection MyDataGridColumns
{
get { return dataGridView1.Columns; }
}
}
public interface IDataGridView
{
DataGridView DataGridView { get; }
}
class ExtendedDataGridViewColumnCollectionEditor : UITypeEditor
{
private Form dataGridViewColumnCollectionDialog;
private ExtendedDataGridViewColumnCollectionEditor() { }
private static Form CreateColumnCollectionDialog(IServiceProvider provider)
{
var assembly = Assembly.Load(typeof(ControlDesigner).Assembly.ToString());
var type = assembly.GetType("System.Windows.Forms.Design.DataGridViewColumnCollectionDialog");
var ctr = type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
return (Form)ctr.Invoke(new object[] { provider });
}
public static void SetLiveDataGridView(Form form, DataGridView grid)
{
var mi = form.GetType().GetMethod("SetLiveDataGridView", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Invoke(form, new object[] { grid });
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
if (provider != null && context != null)
{
var service = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if (service == null || context.Instance == null)
return value;
var host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
if (host == null)
return value;
if (dataGridViewColumnCollectionDialog == null)
dataGridViewColumnCollectionDialog = CreateColumnCollectionDialog(provider);
//Unfortunately we had to make property which returns inner datagridview
//to access it here because we need to pass DataGridView into SetLiveDataGridView () method
var grid = ((IDataGridView)context.Instance).DataGridView;
//we have to set Site property because it will be accessed inside SetLiveDataGridView () method
//and by default it's usually null, so if we do not set it here, we will get exception inside SetLiveDataGridView ()
var oldSite = grid.Site;
grid.Site = ((UserControl)context.Instance).Site;
//execute SetLiveDataGridView () via reflection
SetLiveDataGridView(dataGridViewColumnCollectionDialog, grid);
using (var transaction = host.CreateTransaction("DataGridViewColumnCollectionTransaction"))
{
if (service.ShowDialog(dataGridViewColumnCollectionDialog) == DialogResult.OK)
transaction.Commit();
else
transaction.Cancel();
}
//we need to set Site property back to the previous value to prevent problems with serializing our control
grid.Site = oldSite;
}
return value;
}
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
return UITypeEditorEditStyle.Modal;
}
}
This is because you didn't specify the type of the column. You should give the type of the column when adding a column (for example DataGridViewTextBoxColumn or DataGridViewCheckBoxColumn). In your Form1.cs do the following:
public Form1()
{
InitializeComponent();
DataGridViewColumn dgViewColumn = new DataGridViewTextBoxColumn();//Or DataGridViewCheckBoxColumn
dgViewColumn.DataPropertyName = "dgViewColumn";
dgViewColumn.HeaderText = #"dgViewColumn";
dgViewColumn.Name = "dgViewColumn";
userControl11.MyDataGridColumns.Add(dgViewColumn);
}
#Bioukh answer works in VS2019 and somewhat works in VS2022. However, the results of embedding the DataGridView control in my UserControl then adding and editing the Columns using the answer does not enable those Columns to migrate to another instance of the UserControl. For example: Copy/Paste the UserControl and all of the embedded DataGridView's columns disappear from the new copy.
To Work Around this issue I maintain my DataGridView instances as native and use a public DataGridView property in my UserControl with the binding and docking performed in the property setter. I then drop my_UserControl on my form, drop my_DataGridView on my form, and then set my_UserControl.DataGridView = my_DataGridView. This work around preserves the native properties and behaviors associated with the DataGridView.
In my_UserControl, I have a Panel named "GridPanel" and a VScrollBar. I then added the following property:
///<summary>
/// Associates a native DataGridView with this UserControl
/// then sets the DataGridView.Parent to the Panel in this UserControl
/// and sets the DataGridView.Dock to Fill the Panel
///</summary>
public DataGridView? ContainedDataGridView
{
get
{
try
{
// if we have a DataGridView in our Panel then return it
if ((this.GridPanel.Controls.Count == 1)
&& (this.GridPanel.Controls[0] is DataGridView view))
{
return view;
}
}
catch (Exception ex)
{
//// TODO Handle "ContainedDataGridView get error"
}
// Return null if there is no DataGridView or there was an error checking for it.
return null;
}
set
{
try
{
// Clear the panel to prevent adding more than one DataGridView
this.GridPanel.Controls.Clear();
if (value is not null)
{
this.GridPanel.Controls.Add(value);
value.Parent = this.GridPanel;
value.Dock = DockStyle.Fill;
}
// else the panel remains cleared
}
catch (Exception ex)
{
//// TODO Handle "ContainedDataGridView set error"
}
}
}
The above snippet is coded as C# 10, .NET 6, Windows Forms App, UserControl and tested in Visual Studio 2022 version 17.0.3
Im trying to position a GTK# dialog in the center of a window,also i would like to make the parent window non editable when this dialog appears.
I tried setting the parent property and of the dialog and set it's position to center on parent.(The parent windows position is always centered,the parent appers centered but a portion of it is below the taskbar)
What im i doing wrong?
UPDATE:
I tried setting the transcientfor property.
mywin d = new mywin();
d.Parent = this;
d.WindowPosition = WindowPosition.CenterOnParent;
d.TransientFor = this;
d.WidthRequest = 360;
d.HeightRequest =260;
d.Resizable = false;
d.Show ();
Also i get this error in Application Output when i do this
(myapp:5844): Gtk-WARNING **: Can't set a parent on a toplevel widget
(myapp:5844): Gdk-CRITICAL **: inner_clipboard_window_procedure: assertion 'success' failed
UPDATE:
Calling the dialog from parent
protected void OnButton7Clicked (object sender, EventArgs e)
{
var mydiag = new mydiag( this );
if ( ( (Gtk.ResponseType) mydiag.Run() ) == Gtk.ResponseType.Ok ) {
// do whatever here...
}
}
Dialog code
using System;
namespace myproj
{
public partial class mydiag : Gtk.Dialog
{
public mydiag (Gtk.Window parent)
{
this.Build ();
this.Title = parent.Title + " more info";
this.Icon = parent.Icon;
this.Parent = parent;
this.TransientFor = parent;
this.SetPosition( Gtk.WindowPosition.CenterOnParent );
this.ShowAll();
}
}
}
The problem is being reported here:
(myapp:5844): Gtk-WARNING **: Can't set a parent on a toplevel widget
Your mywin class is not a Gtk.Dialog, but probably a Gtk.Window. You should create your main window this way:
namespace Whatever {
public class MainWindow: Gtk.Window {
public MainWindow()
: base( Gtk.WindowType.Toplevel )
{
this.Title = "Gtk# App";
this.Build();
}
private void Build() {
// create your widgets
}
// more things...
}
Suppose now that you need to open a dialog for some function in your app.
namespace Whatever {
public class MainWindow: Gtk.Window {
// ...more things
private void OnWhatever() {
var dlg = new DlgMoreInfo( this );
if ( ( (Gtk.ResponseType) dlg.Run() ) == Gtk.ResponseType.Ok ) {
// do whatever here...
}
dlg.Destroy();
}
}
}
Finally, you need to create your dialog DlgMoreInfo centered, etc.
namespace Whatever {
public class DlgMoreInfo : Gtk.Dialog {
public DlgMoreInfo(Gtk.Window parent) {
this.Build();
this.Title = parent.Title + " more info";
this.Icon = parent.Icon;
this.TransientFor = parent;
this.SetPosition( Gtk.WindowPosition.CenterOnParent );
this.ShowAll();
}
private void Build() {
// Create widgets here...
// Buttons
this.AddButton( Gtk.Stock.Cancel, Gtk.ResponseType.Cancel );
this.AddButton( Gtk.Stock.Ok, Gtk.ResponseType.Ok );
this.DefaultResponse = Gtk.ResponseType.Ok;
}
}
}
You can only create dialogs which are childs of a top level window; never a window can be a child of another one.
Note that this code does not use the designer of Xamarin Studio. If you use the designer, then call HideAll() just before ShowAll(), if you need to use the widgets, or move the call to Build() after the call to SetPosition().
Hope this helps.
I have a page transition ( a control ) in the MainWindow , I have many user control pages , I want to access the page transition in the MainWindow from my user control page ? How do I do that?
I tried :
Story page = new Story();
NavigationService nav = NavigationService.GetNavigationService(this);
// Navigate to the page, using the NavigationService
// if (nav != null)
// {
// nav.Navigate(page);
MainWindow test = new MainWindow();
test.pageTransition1.ShowPage(page);
// }
Application.Current.MainWindow
Using this you can access the MainWindow from any place.
You could find the WpfPageTransitions.PageTransition control like this from the UserControls code behind:
public static WpfPageTransitions.PageTransition FindPageControl(DependencyObject child)
{
DependencyObject parent= VisualTreeHelper.GetParent(child);
if (parent == null) return null;
WpfPageTransitions.PageTransition page = parent as WpfPageTransitions.PageTransition;
if (page != null)
{
return page;
}
else
{
return FindPageControl(parent);
}
}
Then you can use it like this:
this.FindPageControl(this).ShowPage(...);
Create A Method Inside Main Window for Choosing Page Transition
public void ChangePage()
{
pageTransitionControl.ShowPage(new NewData());
}
Then in Child control
private void btnUpdate_Click(object sender,RoutedEventArgs e)
{
MainWindow win = (MainWindow)Window.GetWindow(this);
win.ChangePage();
}
Can't seem to figure out how to do this. I have an inherited Control: MyControl with a property called MyOtherFont. How do I get MyOtherFont to inherit the ambient value of the Parent control's Font property?
For example, from the designer if I drag this control onto a Form where the font is Segoe UI, it should inherit that value from the Form and not show it as bolded in the property window.
Thanks
Figured it out. Here is a C# example that does exactly what my example describes. Hope this helps someone.
public class MyControl : Control
{
private Font myOtherFont;
public Font MyOtherFont
{
get
{
if (this.myOtherFont == null)
{
if (base.Parent != null)
return base.Parent.Font;
}
return this.myOtherFont;
}
set
{
this.myOtherFont = value;
}
}
private bool ShouldSerializeMyOtherFont()
{
if (base.Parent != null)
if (base.Parent.Font.Equals(this.MyOtherFont))
return false;
if (this.MyOtherFont == null)
return false;
return true;
}
private void ResetMyOtherFont()
{
if (base.Parent != null)
this.MyOtherFont = base.Parent.Font;
else
this.MyOtherFont = Control.DefaultFont;
}
}
in vb6 i can easily get the value from childwindow to another childwindow.. for example frm1.textbox1.text = frm2.listview.item.selectedindex... how can i do this in wpf?
i have two child window named EmployeProfile and the other one is PrintEmpProfile... in EmployeeProfile window, there is a listview... what i want is if I'm going to click the print button, i can get the value from EmployeeProfile listview....
so far this is what's I've got. this code is inside of PrintEmpProfile
DataTable table = new DataTable("EmpIDNumber");
table.Columns.Add("IDNum", typeof(string));
for (int i = 1; i <= 100; i++)
{
table.Rows.Add(new object[] { EmployeeProfile.????? });
}
i don't know how to get all values from EmployeeProfile listview.
Whenever you open a child window put a reference of the new child window into a collection. I ssume that MyChild is your child window defined in XAML like:
<Window
x:Class="TEST.MyChild"
...
You can define a static list holding your child windows in App.xaml.cs
public partial class App : Application
{
public static List<MyChild> Children
{
get
{
if (null == _Children) _Children = new List<MyChild>();
return _Children;
}
}
private static List<MyChild> _Children;
}
Whenever you open child window add it into this collection like:
MyChild Child = new MyChild();
App.Children.Add(Child);
Child.Show();
You should also remove child from this collection when you close your child window. You can do this in Closed event of the window. Define closed vent in XML:
Closed="MyChild_Closed"
And in code behind:
private void MyChild_Closed(object sender, EventArgs e)
{
// You may check existence in the list first in order to make it safer.
App.Children.Remove(this);
}
Whenever a child window wants to access ListView of other child window then it gets reference of the child from the collection and then call ListView defined in XAML directly.
MyChild ChildReference = App.Children.Where(x => x.Title == "Child Title").FirstOrDefault();
if (null != ChildReference)
{
ChildReference.listview.SelectedIndex = ...
}
You can create Property Of listview .
public ListView EmployeeListView
{
get
{
return IdOfYourListView;
}
set
{
IdOfYourListView = value;
}
}
Now on PrintEmpProfile Create object of EmployeeProfile
EmployeeProfile empf = new EmployeeProfile();
ListView MyListView = empf.EmployeeListView;