i'm coding a c# application using WPF
i have a main Window which contain a Grid named " SelectionGrid ". this grid will contain Control User, my problem is that i want to modify ( add/delete) Control User in that grid from a USER CONTROL itself
for example:
SelectionGrid host the User Control " Menu" in this menu there a button, i want from this button to remove the Menu User Control and add another User Control in this SelectionGrid
main window code :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
UserControl usc = new Menu();
SelectionGrid.Children.Add(usc);
}}
Menu User Control code :
public partial class Menu : UserControl
{
public Menu()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// want to add Another User Control in SelectionGrid
}
Firstly,put your userControl in some container control like Grid.Then you can easily access and modify the grid from the usercontrol as follows:
var parent = (Grid)this.Parent;
///do what you want to do with parent
A bit of knowledge-sharing : The below code can be used to access the parent of controls like Page,UserControl :
public static T FindParent(DependencyObject child)
{
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null)
return null;
T parent = parentObject as T;
if (parent != null)
return parent;
else
return FindParent<T>(parentObject);
}
private void test()
{
ControlTypeHere parent = FindParent<ControlTypeHere>(this);
Hope this helps :)
Related
I am trying to change the label and text of a label which is inside a UserControl from within a Parent Form method at runtime.
So within the method in parent Form I do the following to change the label properties which is inside a UserControl
public partial class Form : Form
{
public void Form_Method()
{
UserControl uc = new UserControl();
uc.UpdateLabel(true);
}
}
And the custom method inside my UserControl
public partial Class UserControl : UserControl
{
public void UpdateLabel(bool value)
{
if (value)
{
lbl.Text = "This";
lbl.Forecolor = Color.Green;
}
if (value == false)
{
lbl.Text = "That";
lbl.Forcolor = Color.Red;
}
}
}
However when I navigated to the UserControl the label properties have not changed as I was creating a new instance of the usercontrol on the fly which
technically disappears after the method ends.
So I tried creating a public property of the actual UserControl as follows
public partial class Form : Form
{
public UserControl _uc;
public void Form_Method()
{
UserControl uc2 = new UserControl();
uc2.UpdateLabel(true);
_uc = uc2;
}
}
However it has no effect whatsoever? I have come across info of using Events or Delegates am not sure if they are the correct process for what am trying to do?
I have a UserControl which contains a TabControl. I enabled the designer of the TabControl and its TabPages so the user can add/remove/modify tab pages and add controls to tab pages.
When I add my UserControl to the Form and add controls on tab pages it's OK and controls can be added/removed/changed properly until I build the project or save changes and close and reopen the form.
When I build the project, every changes that I'd made in tab pages and each controls which I added to tab pages are removed. The controls exists on designer.cs but they doesn't show on tab pages.
Why do the controls I added to tab pages of the TabControl of my UserControl disappear after rebuild?
My user control source code:
Note: tbBody is a TabControl
[Designer(typeof(MainDesigner))]
public partial class MZTabControl : UserControl
{
private bool isdesign = false;
private bool allowtbodyresize = false;
public MZTabControl()
{
InitializeComponent();
}
[Category("MZ TabControl"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public TabControl TabControlArea
{
get
{
return tbBody;
}
}
}
My designer source code:
public class MainDesigner : ParentControlDesigner
{
private DesignerVerbCollection dvc = new DesignerVerbCollection();
public override void Initialize(System.ComponentModel.IComponent component)
{
base.Initialize(component);
if (this.Control is MZTabControl)
{
this.EnableDesignMode(((MZTabControl)this.Control).TabControlArea,
"TabControlArea");
var uc = (MZTabControl)component;
foreach (TabPage tbpg in uc.tbBody.TabPages)
{
EnableDesignMode(tbpg, tbpg.Name);
}
}
}
}
Before rebuild or clean: Screenshot
After rebuild or clean: Screenshot
The designer of Form cant't see those TabPag controls which you created in the UserControl.
You can remove all items from TabPages collection of the TabControl in your UserControl. If you need the TabControl have some pages after adding to Form you can add some tab pages in InitializeNewComponent method of designer of your user control. Then user can change those pages or add/remove pages to the TabControl of your UserControl and all tabs and their contents will be serialized because this way the Form designer can see those tabs.
UserControl1
Create a public property for the TabControl and decorate it with DesignerSerializationVisibility by passing DesignerSerializationVisibility.Content as value to say the designer serialize the content of control:
using System.ComponentModel;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[Designer(typeof(UserControl1Designer))]
public partial class UserControl1 : UserControl
{
public UserControl1() { InitializeComponent(); }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public TabControl MyTabControl
{
get { return this.tabControl1; }
}
private void InitializeComponent()
{
this.tabControl1 = new System.Windows.Forms.TabControl();
this.SuspendLayout();
this.tabControl1.Name = "tabControl1";
this.tabControl1.Dock = DockStyle.Fill;
this.Controls.Add(this.tabControl1);
this.Name = "UserControl1";
this.ResumeLayout(true);
}
private System.Windows.Forms.TabControl tabControl1;
}
UserControl1Designer
Enable the designer of TabControl using EnableDesignMode method of the designer. Also initialize the TabControl by adding 2 TabPage like the job that the original control performs. To do so, you should use IDesignerHost service like below.
public class UserControl1Designer : ParentControlDesigner
{
public override void Initialize(System.ComponentModel.IComponent component)
{
base.Initialize(component);
this.EnableDesignMode(((UserControl1)this.Control).MyTabControl, "MyTabControl");
}
public override void InitializeNewComponent(System.Collections.IDictionary values)
{
base.InitializeNewComponent(values);
AddTab();
AddTab();
}
private void AddTab()
{
TabControl tabControl = ((UserControl1)this.Control).MyTabControl;
var svc = (IDesignerHost)this.GetService(typeof(IDesignerHost));
if (svc != null)
{
var tab1 = (TabPage)svc.CreateComponent(typeof(TabPage));
tab1.Text = tab1.Name;
tab1.UseVisualStyleBackColor = true;
tabControl.TabPages.Add(tab1);
var property = TypeDescriptor.GetProperties(tabControl)["Controls"];
base.RaiseComponentChanging(property);
base.RaiseComponentChanged(property, null, null);
}
}
}
Then if you drag UserControl1 from toolbox and add it to the form, you can see the user control contains an editable tab control which contains 2 editable tab pages and all changes will be serialized and be persisted.
Note
If you have a single or two pages in the TabContrl of your UserControl and you want to make them editabe, you should create public properties in your UserControl and enable designer of each tab page with name of corresponding property.
Consider this note from remarks part of EnableDesignMode:
The child does not directly participate in persistence, but it will if
it is exposed as a property of the main control.
UserControl
You should have a public property for each TabPage which you want to expose:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public TabControl MyTabControl
{
get { return this.tabControl1; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public TabPage T1
{
get { return this.tabPage1; }
}
Designer
public class MyUserControl2Designer : ParentControlDesigner
{
public override void Initialize(System.ComponentModel.IComponent component)
{
base.Initialize(component);
this.EnableDesignMode(((UserControl2)this.Control).MyTabControl, "MyTabControl");
this.EnableDesignMode(((UserControl2)this.Control).T1, "T1");
}
}
How can I call method in UC from MainWindow? In my app I use MainWindow + UserControls + TabControl (one user control = one tabitem, as firefox). I would call method in user control when I change tabitem. I'll explain this with an example.
UserControl code:
MainWindow mw;
public userControl(MainWindow main)
{
this.mw = main;
InitializeComponent();
LoadData();
}
public void LoadData()
{
using (var mod = new Data())
{
try
{
var query = (from c in mod.table
select c).ToList();
dataGrid.ItemsSource = null;
dataGrid.ItemsSource = query;
}
catch {}
}
}
MainWindow code:
public void RefreshUserControl(string userControlName)
{
switch (userControlName)
{//... others UC
// ....
case "userControl":
userControl ue = new userControl(this);
ue.LoadData();
break;
}
}
private void tabUC_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var item = sender as TabControl;
var selected = item.SelectedItem as TabItem;
if (selected != null)
{
RefreshUserControl(selected.Name.ToString());
}
}
Generally, example - When I change tabitem on "userControl" then refresh datagrid on this usercontrol. Please help
Although I would suggest you to change your approach to create UCs here so that there is no dependency on MainWindow in UC but if you want to continue with it for now,
you can have an Event in your Main window
Raise that event when tab selection is changed
listen to that event in UC as you have MainWindow reference
do whatever you want to do in the event handler in UC
I am trying to access parent window from user control.
userControl1 uc1 = new userControl1();
mainGrid.Children.Add(uc1);
through this code I load userControl1 to main grid.
But when I click on a button inside userControl1 then I want to load another userControl2 into mainGrid which is in main window?
Have you tried
Window yourParentWindow = Window.GetWindow(userControl1);
This gets the root level window:
Window parentWindow = Application.Current.MainWindow
or the immediate parent window
Window parentWindow = Window.GetWindow(this);
The only reason why the suggested
Window yourParentWindow = Window.GetWindow(userControl1);
didnt work for you is because you didn't cast it to the right type:
var win = Window.GetWindow(this) as MyCustomWindowType;
if (win != null) {
win.DoMyCustomWhatEver()
} else {
ReportError("Tough luck, this control works only in descendants of MyCustomWindowType");
}
Unless there has to be way more coupling between your type of windows and your control, I consider your approach bad design .
I'd suggest to pass the grid on which the control will operate as a constructor parameter, make it into a property or search for appropriate (root ?) grid inside any Window dynamically.
Modify the constructor of the UserControl to accept a parameter of MainWindow object. Then pass the MainWindow object to the UserControl when creating in the MainWindow.
MainWindow
public MainWindow(){
InitializeComponent();
userControl1 uc1 = new userControl1(this);
}
UserControl
MainWindow mw;
public userControl1(MainWindow recievedWindow){
mw = recievedWindow;
}
Example Event in the UserControl
private void Button_Click(object sender, RoutedEventArgs e)
{
mw.mainGrid.Children.Add(this);
}
Thanks for help me guys. i got another solution
((this.Parent) as Window).Content = new userControl2();
this is perfectly works
Make a static instance of main window ,you can simply call it in your user control:
See this example:
Window1.cs
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
_Window1 = this;
}
public static Window1 _Window1 = new Window1();
}
UserControl1.CS
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void AddControl()
{
Window1._Window1.MainGrid.Children.Add(usercontrol2)
}
}
I want to close a window form that is hosting a WPF user control. Something like this as used while closing a current form in window application. But for WPF application I am not able to get reference to user controls parent
How to get Form which is hosting this control so that I can close my form
this.Close()
Add to your WpfControl property
public Form FormsWindow { get; set; }
In your WinForm add event handler for ElementHost's event ChildChanged:
using System.Windows.Forms.Integration;
public MyForm() {
InitializeComponent();
elementHost.ChildChanged += ElementHost_ChildChanged;
}
void ElementHost_ChildChanged(object sender, ChildChangedEventArgs e) {
var ctr = (elementHost.Child as UserControl1);
if (ctr != null)
ctr.FormsWindow = this;
}
After that you can use the FormsWindow property of your WpfControl to manipulate window. Example:
this.FormsWindow.Close();
An alternative solution could be,
Window parent = Window.GetWindow(this);
parent.Close();
Just want to add to #The_Smallest's otherwise very clear answer.
If you just copy and past the event handler code, you will still need to set your Forms's ChildChanged event to ElementHost_ChildChanged. I missed that step and spent 30 minutes trying to figure out why FormsWindow was null.
In order to call the Form object of the MyControl class already. We have in it a Form field to which we pass an instance object open Form. Having an assigned object we can freely manipulate it (including also call the function form.Close ();
WPF Control (with XAML):
public class MyControl : UserControl
{
public Form form = null;
public MyControl()
{
InitializeComponent();
this.PreviewKeyDown += new KeyEventHandler(HandleEsc);
}
private void HandleEsc(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
form.Close();
}
}
}
Form:
public class MainForm
{
//...
public Form form = null;
public MainForm(MyControl myControl)
{
InitializeComponent();
//...
myControl.form = (Form)this;
}
}