how to access SimpleChildWindow from other UserControl - c#

I have two user controls in wpf and i have defined simple child window in both of them now i want to access them in the way like Uc1 have child1 and Uc2 have child2 i want to access child2 from Uc1 and vice versa from code behind.

The way I would do that is, via the mainwindow. You don't want to create dependencies between both the controls. This is because of reusing the usercontrols.
This is an example passing the childs thru an event. I wouldn't pass the mainwindow as a reference into the UserControl's constructor.
If you want to do that, you should create an interface and implement it on the MainWindow and pass it as an interface.
like:
UC1-(event)>MainWindow-(methodcall)>UC2-(methodcall)>UC2.child
Pseudo code:
// event args.
public class RequestChildEventArgs : EventArgs
{
public Child2 Child { get;set; }
}
public class UC1
{
// do something when you need the child2
public void DoSomething()
{
var child2 = GetChild2();
if(child2 == null)
// cry.
}
// this method requests a reference of child2
private Child2 GetChild2()
{
// check if the event is assigned.
if(RequestChild == null)
return null;
RequestChildEventArgs args = new RequestChildEventArgs();
RequestChild2(this, args);
return args.Child;
}
public event EventHandler<RequestChildEventArgs> RequestChild2;
}
// user control 2
public class UC2
{
public Child2 Child2 { get; } = new Child2();
}
// the mainwindow that tunnels the Child2
public class MainWindow
{
private UC1 _uc1;
private UC2 _uc2;
public MainWindow()
{
_uc1 = new UC1();
_uc2 = new UC2();
_uc1.RequestChild2 += (s, e) => e.Child = _uc2.Child2;
}
}
the visa versa version:
Pseudo code:
// event args.
public class RequestChildEventArgs<T> : EventArgs
{
public T Child { get; set; }
}
public class UC1
{
public Child1 Child1 { get; } = new Child1();
// do something when you need the child2
public void DoSomething()
{
var child2 = GetChild2();
if (child2 == null)
// cry.
}
// this method requests a reference of child2
private Child2 GetChild2()
{
// check if the event is assigned.
if(RequestChild2 == null)
return null;
RequestChildEventArgs<Child2> args = new RequestChildEventArgs<Child2>();
RequestChild2(this, args);
return args.Child;
}
public event EventHandler<RequestChildEventArgs<Child2>> RequestChild2;
}
// user control 2
public class UC2
{
public Child2 Child2 { get; } = new Child2();
// do something when you need the child1
public void DoSomething()
{
var child1 = GetChild1();
if(child1 == null)
// cry.
}
// this method requests a reference of child1
private Child1 GetChild1()
{
// check if the event is assigned.
if(RequestChild1 == null)
return null;
RequestChildEventArgs<Child1> args = new RequestChildEventArgs<Child1>();
RequestChild1(this, args);
return args.Child;
}
public event EventHandler<RequestChildEventArgs<Child1>> RequestChild1;
}
// the mainwindow that tunnels the Childs
public class MainWindow
{
private UC1 _uc1;
private UC2 _uc2;
public MainWindow()
{
_uc1 = new UC1();
_uc2 = new UC2();
_uc1.RequestChild2 += (s, e) => e.Child = _uc2.Child2;
_uc2.RequestChild1 += (s, e) => e.Child = _uc1.Child1;
}
}
This way is you usercontrol not dependend on the mainwindow or singleton objects.

Related

How to maintain object in multiple instances - C#

I am maintaining one object(Parent) in my MainWindow class. That Parent Object is being passed to another object(objMyClass). Now If I update Parent Object in mainwindow, it is not reflecting it in objMyClass object. Below is the code.
using System.Windows;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public Parent objParent;
public MyClass objMyClass;
public MainWindow()
{
InitializeComponent();
objParent = new Parent();
objMyClass = new MyClass(objParent);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if ((bool)checkPWB.IsChecked)
objParent = new Child1();
else
objParent = new Child2();
objParent.Display();
objMyClass.par.Display();
}
}
public class MyClass
{
public Parent par;
public MyClass(Parent p)
{
par = p;
}
}
public class Parent
{
public virtual void Display()
{
MessageBox.Show("I am Parent");
}
}
public class Child1 : Parent
{
public override void Display()
{
MessageBox.Show("I am Child1");
}
}
public class Child2 : Parent
{
public override void Display()
{
MessageBox.Show("I am Child2");
}
}
}
When I click the button, I am creating a new object (Child1) and assigning to my parent object which doesn't reflect it in ObjectMyClass.
Any help on this is appreciated.
To refer to the same field you can use Func<Parent> that would return current value of the filed:
public class MyClass
{
private Func<Parent> getParent = null;
public Parent par => getParent();
public MyClass(Func<Parent> getParent)
{
this.getParent = getParent;
}
}
and construct your class as
objMyClass = new MyClass(() => objParent);
This way instead of having its own reference to Parent object that contains copy of the original value of the parameter (as in code in the question) this MyClass will always return current value of objParent field and indeed reflect changes to that field.
Alternatively you can just change par property directly instead of changing objParent.

C# Calling a main form method via other class

I have this project where i contain all my panel instances in my main form.
PanelA aPanelA = new PanelA;
PanelB aPanelB = new PanelB;
This is the form where the program.cs load when it starts.
Because i would like to have a centralize place for each panel calling one another method within them hence i declare them in main. In main, i also make some methods doing certain function in these panel since they are declare in main.
void setPanelA (int iNumber){...}
void setPanelB (string strString){...}
The problem is how would a widget in PanelA call the method setPanelB() via main?
Main.setPanelB("Hello World);
I know i can declare PanelA and PanelB as static. But is this the only way to do it? Because if i declare static to both Panel, i will need to declare some instances within Panel as static too..
I also do not wish to declare PanelA in PanelB or via versa because i could have many type of panels and this would make my code very untidy.
*Edited I had add a sample code here
namespace TestPanel
{
public partial class Form1 : Form
{
PanelA aPanelA = new PanelA();
PanelB aPanelB = new PanelB();
//IT IS POSSIBLE TO HAVE TENS OF DIFFERENT TYPE OF PANEL
public Form1()
{
InitializeComponent();
}
//CENTRAL LOCATION WHERE ALL PANEL COULD CALL EACH OTHER METHOD
public void setPanelACentral(int iNew)
{
aPanelA.setPanelA(iNew);
}
public void setPanelBCentral(string strNew)
{
aPanelB.setPanelB(strNew);
}
}
public class PanelA
{
int i = 0;
public void setPanelA(int iNew)
{
i = iNew;
}
}
public class PanelB
{
string str = "";
public void setPanelB(string strNew)
{
str = strNew;
}
//PROBLEM HERE HOW TO ACCESS MAIN setPanelACentral
public void changePanelA()
{
int i = 1000;
Form1.setPanelACentral(i); //<- This the part where i am asking
}
}
}
The following code demonstrates adding Events to both your Panel types and Form1. By doing this, you can raise an event in your Panel that Form1 will have registered to handle.
public partial class Form1 : Form
{
protected EventHandler<PanelEventArg> OnSetPanelA = new EventHandler<PanelEventArg>((sender, e) => { }); //stub
protected EventHandler<PanelEventArg> OnSetPanelB = new EventHandler<PanelEventArg>((sender, e) => { }); //stub
protected List<PanelBase> panels;
public Form1() : base()
{
panels = new List<PanelBase>
{
new PanelA(),
new PanelB()
};
foreach (var panel in panels)
{
OnSetPanelA += panel.OnSetPanel;
OnSetPanelB += panel.OnSetPanel;
panel.OnSomeEvent += Form1_OnSomeEvent;
}
foreach (var panel in panels.OfType<PanelB>())
{
panel.OnChangePanelA += Form1_OnChangePanelA;
}
InitializeComponent();
}
protected void SetPanelA(int iNew)
{
foreach (var panel in panels.OfType<PanelA>())
{
panel.SetPanelA(iNew);
OnSetPanelA(this, new PanelEventArg
{
Panel = panel
});
}
}
protected void SetPanelB(string strNew)
{
foreach (var panel in panels.OfType<PanelB>())
{
panel.SetPanelB(strNew);
OnSetPanelA(this, new PanelEventArg
{
Panel = panel
});
}
}
protected void Form1_OnSomeEvent(object sender, EventArgs e)
{
// handles events raised by the panel.
}
protected void Form1_OnChangePanelA(object sender, int iNew)
{
SetPanelA(iNew);
}
}
Helper Types I'm including: PanelEventArg, PanelBase
public class PanelEventArg : EventArgs
{
public PanelBase Panel { get; set; }
}
public class PanelBase //: Panel
{
public EventHandler OnSomeEvent = new EventHandler((sender, e) => { }); //stub;
public void OnSetPanel(object sender, PanelEventArg e)
{
if (!Equals(e.Panel, this))
{
//the panel being set is not this panel instance
}
}
}
Declaring PanelA and PanelB, with inheritance and new Event for PanelB
public class PanelA : PanelBase
{
int i = 0;
public void SetPanelA(int iNew)
{
i = iNew;
}
}
public class PanelB : PanelBase
{
public EventHandler<int> OnChangePanelA = new EventHandler<int>((sender, e) => { }); //stub
string str = "";
public void SetPanelB(string strNew)
{
str = strNew;
}
//PROBLEM HERE HOW TO ACCESS MAIN setPanelACentral
public void ChangePanelA()
{
OnChangePanelA(this, 1000);
}
}

Custom MenuItemPanel (How add Items on Design Time?)

The problem is as follows:
In my User Control i have Label List (List ) which fills adding Labels which UC through a "Smart Tag" (using a DesignerActionMethodItem).
The problem is that it works correctly when we are in design time, for example, I add 3 items at design time, but when I test the application these items disappear as if they had never added.
P.S.:
I have:
MyControl class,
[Designer(typeof(MenuItemPanelDesigner ))]
public partial class MenuItemPanel : UserControl
{
private List<Label> _listaItems;
public MenuItemPanel()
{
InitializeComponent();
}
public List<Label> ListaItems
{
get
{
if (this._listaItems == null)
{
this._listaItems = new List<Label>();
}
return this._listaItems;
}
}
public void AgregarItem()
{
Label nuevoItem = new Label();
nuevoItem.Text = "Item " + this._listaItems.Count;
nuevoItem.AutoSize = false;
nuevoItem.TextAlign = ContentAlignment.MiddleCenter;
nuevoItem.Cursor = Cursors.Hand;
this.ListaItems.Add(nuevoItem);
this.Controls.Add(nuevoItem);
nuevoItem.Dock = DockStyle.Top;
nuevoItem.Height = 50;
}
}
MyControlDesigner class
class MenuItemPanelDesigner : System.Windows.Forms.Design.ControlDesigner
{
private DesignerActionListCollection actionLists;
public override DesignerActionListCollection ActionLists
{
get
{
if (null == actionLists)
{
actionLists = new DesignerActionListCollection();
actionLists.Add(new MenuItemPanelDesignerActionList(this.Component));
}
return actionLists;
}
}
}
and MyControlDesignerActionList
class MenuItemPanelDesignerActionList : DesignerActionList
{
private MenuItemPanel colUserControl;
private DesignerActionUIService designerActionUISvc = null;
//The constructor associates the control with the smart tag list.
public MenuItemPanelDesignerActionList(IComponent component) : base(component)
{
this.colUserControl = (MenuItemPanel)component;
this.designerActionUISvc = (DesignerActionUIService)GetService(typeof(DesignerActionUIService));
}
// Implementation of this abstract method creates smart tag items,
// associates their targets, and collects into list.
public override DesignerActionItemCollection GetSortedActionItems()
{
DesignerActionItemCollection items = new DesignerActionItemCollection();
//Define static section header entries.
items.Add(new DesignerActionHeaderItem("Items"));
items.Add(new DesignerActionMethodItem(this,"AgregarItem","Agregar Item"));
return items;
}
// Metodos
public void AgregarItem()
{
this.colUserControl.AgregarItem();
}
}

Efficient technique for sending text messages to UI

I have a WPF Windows app. The viewmodel calls a method in the format of Model.TrySomething(), which returns a boolean if anything in TrySomething logically fails. If false is returned, the UI can throw a message back to the user.
What is the best way to bubble this message up from the model?
This is how we do it on our projects. Works fine:
// your event args might include more properties
public class ShowMessageBoxEventArgs : System.EventArgs
{
public string Title { get; set; }
public string Text { get; set; }
}
// example of your model base
public class MyModelBase
{
public event EventHandler<ShowMessageBoxEventArgs> ShowMessageBox;
protected void RaiseShowMessageBox(string title, string text)
{
if (ShowMessageBox == null)
return;
var _Args = new ShowMessageBoxEventArgs
{
Text = text,
Title = title
};
ShowMessageBox(this, _Args);
}
}
// for this sample, this is your view model
public class MyModel : MyModelBase
{
public void DoSomething()
{
// TODO: Do Something
base.RaiseShowMessageBox("DoSomething", "Complete!");
}
}
// this is your window or in app.xaml.cs (where we do it)
public partial class MainWindow : Window
{
MyModel m_MyModel = new MyModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = m_MyModel;
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
bool m_Loaded = false; // only once
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
if (m_Loaded)
return;
m_Loaded = true;
// allow model to show messagebox
m_MyModel.ShowMessageBox += (s, arg) =>
{
MessageBox.Show(arg.Text, arg.Title);
};
}
}
Best of luck!
If the message which you want to display is a modal dialog, you can write a service (lets name it MessageDialogService) which is injected in your viewmodel and then call a MessageDialogService.Show() method. This method creates a new WPF window and shows the message.
This service can then be used in any of your ViewModels to show messages.

How to enable shortcuts in child form

I have wrote a frame application, it's a windows form app as parent form.When it starts, it will find dlls in /modules and load them as extensions. And when I click the menuItem in the parent form, the specific dll will work.If the dll is a Form app, it will show.But when i try to use shortcuts(only build-ins,eg : CTRL-C...) in the childForm ,the hotkeys does not work. Anyone kindly tell me why and how can i fix the issue? Here's my code:
//parent.exe--ModuleEntrance.cs
public abstract class ModuleEntrance {
public abstract string[] GetMenuNames();
public abstract string[] GetMenuItemNames();
public abstract EventHandler[] GetEventHandlers();
}
//parent.exe--ParentForm.cs
public partial class MDIParent : Form {
public MDIParent() { //CTOR
InitializeComponent();
ModuleEntrance oneEntrance;
string oneMenuName, oneMenuItemName;
ToolStripMenuItem theMenu, theMenuItem;
for(){ //iterate dlls in /modules, if it implement ModuleEntrance, load it.
//And 1)load menu&menuItem.
//2) connect handler to menuItem.click through
//<code:theMenuItem.Click += new EventHandler(oneEntrance.GetEventHandlers()[i]);>
}
}
//--------------
//child.dll-- EntranceImp.cs //implement AC
public class EntranceImp : ModuleEntrance {
public override string[] GetMenuNames() {
return new string[] { "MENU"};
}
public override string[] GetMenuItemNames() {
return new string[] { "OpenChildForm"};
}
public override EventHandler[] GetEventHandlers() {
return new EventHandler[]{
(EventHandler)delegate(object sender, EventArgs e) { //Anonymous method
childForm form = new childForm();
//find MDIparent and connect them
ToolStripMenuItem mi = (ToolStripMenuItem)sender;
form.MdiParent = (Form)(mi.OwnerItem.Owner.Parent); //It works!
form.Show();
}
};
}
}
//child.dll--childForm.dll
//...
The child form has to notify the parent form about the key-down events somehow.
A way to do this is to have the child form expose key-down events that the parent form can listen to. Remember to remove the parent event handlers every time that you change child form, or you'll end up with a memory leak since objects are not garbage collected until you release all references to them, including event handlers.
class Parent
{
KeyEventHandler KeyDownHandler;
public Parent()
{
KeyDownHandler = new KeyEventHandler(form_TextBoxKeyDown);
}
void SetChildForm(Child form)
{
form.TextBoxKeyDown += KeyDownHandler;
}
void RemoveChildForm(Child form)
{
form.TextBoxKeyDown -= KeyDownHandler;
}
void form_TextBoxKeyDown(object sender, KeyEventArgs e)
{
if (e.Control)
{
switch (e.KeyCode)
{
case Keys.C:
break;
case Keys.X:
break;
case Keys.V:
break;
}
}
}
}
class Child
{
TextBox txtBox;
public event KeyEventHandler TextBoxKeyDown;
internal Child()
{
txtBox.KeyDown += new KeyEventHandler(txtBox_KeyDown);
}
void txtBox_KeyDown(object sender, KeyEventArgs e)
{
if (TextBoxKeyDown != null)
TextBoxKeyDown(sender, e);
}
}

Categories

Resources