Reuirement :
Need to show all child pages in a master layout. Without opening as new window i mean it should not be visible as separate window from main window
Solution i figured :
I used content presenter in main page.
Create all other pages as User controls.
On click of menu ViewWindow.Content = new SalesEntry();
By using that i am showing that.
Problem :
To close that user control i used a button click (button present inside the user control)
to preform this.Visibility = Visibility.Hidden;
But every time when user request this page the page is initialized and shown.
So, whats the best approach for this to overcome or any other way to solve this.
(I was told not to use any framework as a project requirement)
I am very new WPF..
Please help me in this..
What you are doing is fine, I don't really understand the problem here but I will tell you how I would do it.
You will have a parent view, a Window. You will have many childs, UserControl's.
Inside your window, you should have a way of selecting which child to show. This can be done using buttons or a menu.
When you select a child, you instantiate it as an object and subscribe to its exit event. When this event is fired by the child, you remove that child from your childs in the parent window.
// This one defines the signature of your exit event handler
public delegate void OnExitHandler(UserControl sender);
// This is your child, UserControl
public partial class MyChild : UserControl
{
public event OnExitHandler OnExit;
public MyChild()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.OnExit(this);
}
}
// This is your parent, Window
public partial class MainWindow : Window
{
private MyChild _control; // You can have a List<UserControl> for multiple
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_control = new MyChild();
_control.OnExit += _control_OnExit; // Subscribe to event so you can remove the child when it exits
_content.Content = _control; // _content is a ContentControl defined in Window.xaml
}
private void _control_OnExit(UserControl sender)
{
if(sender == _control)
{
// Or if you have a collection remove the sender like
// _controls.Remove(sender);
_control = null;
_content.Content = null;
}
}
}
If your problem is something else, please comment.
Related
I have a main form that has buttons, the role of one of them in disabling all controls of the form in general.
I also have a child form that inherits the buttons and the actions of them, as I could prevent the events of the parent form at a certain point from running that is, temporarily remove the event, for example if the user has a text and does not fill it out and gives the button I do not want anything to be disabled
I think there is a way in c# that like the "eventname"=- I don't remember well
This is an example of my base or parent form, with a button that does actions
Parent Form
namespace WindowsFormsApp1
{
public partial class BaseMantenimiento1 : DevExpress.XtraEditors.XtraForm
{
public BaseMantenimiento1()
{
InitializeComponent();
}
private void BaseMantenimiento1_Load(object sender, EventArgs e)
{
Guardar.Enabled = false;
Cancelar.Enabled = false;
controles.habilitarcontroles(false, xtraTabControl1);
}
private void Nuevo_Click(object sender, EventArgs e)
{
Guardar.Enabled = true;
Cancelar.Enabled = true;
Editar.Enabled = false;
Buscar.Enabled = false;
Nuevo.Enabled = false;
controles.habilitarcontroles(true, xtraTabControl1);
}
This is my child form with its basic code
child form
public partial class Mantenimiento_Empresas : BaseMantenimiento1
{
public Mantenimiento_Empresas()
{
InitializeComponent();
}
What I wanted was that if in the child form I gave the button save, but they did not fill the textbox well, then the event that this inherits from its parent form is not executed, so I took the event and then below if everything is fine I trigger the event of the parent with
base.Save_Click(null, null);
I found what I was looking for, in the same space where the components are initialized I must place the following
public Mantenimineto_Bicicletas()
{
InitializeComponent();
Save.Click -= base.Save_Click;
}
I want my UserControl (at the middle-top in the image) to lose focus when I click outside of it, anywhere.
I have tried this:
private void Form1_Click(object sender, EventArgs e)
{
ActiveControl = null;
}
It only works when I click the Form itself, the TrackBar and the MediaPlayer. It doesn't work when I click other controls, even the FlowLayoutPanel.
What can I do about it?
Eric,
To remove the focus from an item in your custom control, you will need some other focusable control to pass the focus to. I would do something like this:
private void StealFocus() => lbl_SomeLabel.Focus();
And then drop StealFocus() in your form's click event handler:
private void Form1_Click(object sender, EventArgs e) => StealFocus();
and any other control the user might click that doesn't execute a command.
Note that you cannot set focus to the Form. Container controls like Form and Panel will pass the Focus on to their first child control. Which could be the custom control you wanted to remove focus from.
You can use a general purpose Message handler/dispatcher:
Make your Forms that need to provide control over Mouse events implement IMessageFilter, so these Forms will know beforehand what messages are sent to which child Control, what kind of event is generated and any other details that may be useful, such as the position of the Mouse pointer when the event is generated. Mouse related messages are generated in any case, no matter whether you click on a Control that usually cannot get Focus, as the Form itself, or a Panel etc.
Your Forms also implement another Interface that just defines a public event that interested parties can subscribe to in order to receive fresh notifications about these events.
This also allows Control to detect whether the Parent Form is actually a Mouse Event notifier guy.
When a Mouse event is notified (here, just the event generated when a WM_LBUTTONDOWN message is received), subscribers of the event(s) can decide to act upon it. In your case, you can call the SelectNextControl() method of the Parent Form to set a different ActiveControl, only when your UserControl has the Focus and a MouseDown event is generate outside its bounds.
Call Application.AddMessageFilter() before the Form is constructed, passing the Form instance itself, since this Form implements the IMessageFilter interface.
Remove the message filter when the Form closes.
Form side:
add a message filter to capture a mouse down event (WM_LBUTTONDOWN) and rise an event to notify the subscribers of the location where the event is generated and which is the Control that will be affected (passing its Handle).
public partial class SomeForm : Form, IMessageFilter, IMouseHandler {
private const int WM_LBUTTONDOWN = 0x0201;
public event EventHandler<MouseDownEventArgs> MouseEvent;
public SomeForm() => InitializeComponent();
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN) {
var pos = MousePosition;
MouseEvent?.Invoke(this, new MouseDownEventArgs(m.HWnd, pos));
}
return false;
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if (!DesignMode) Application.AddMessageFilter(this);
}
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
if (!DesignMode) Application.RemoveMessageFilter(this);
}
}
UserControl part:
if the Parent Form implements IMouseHandler, subscribe to its MouseEvent. When the event is raised, verify that the UserControl is the current ActiveControl (it contains the Focus) and that the Mouse event is generated outside its bounds. If these conditions are met, call the Parent Form's SelectNextControl() method to move the Focus elsewhere.
The bool m_MouseEventSubscribed is there because a UserControl may regenerate its Handle more than once in its life-time.
public partial class MyUserControl : UserControl
{
private bool m_MouseEventSubscribed = false;
public MyUserControl() => InitializeComponent();
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
var form = this.ParentForm;
if (form != null && form is IMouseHandler && !m_MouseEventSubscribed) {
m_MouseEventSubscribed = true;
((IMouseHandler)form).MouseEvent += (s, a) => {
if (this.ContainsFocus && !this.ClientRectangle.Contains(PointToClient(a.Position))) {
form.SelectNextControl(this, true, true, false, true);
}
};
}
}
}
IMouseHandler Interface:
public interface IMouseHandler
{
event EventHandler<MouseDownEventArgs> MouseEvent;
}
Custom EventArgs class:
using System;
using System.Drawing;
public class MouseDownEventArgs : EventArgs
{
public MouseDownEventArgs() { }
public MouseDownEventArgs(IntPtr hWnd, Point point)
{
this.ControlHandle = hWnd;
this.Position = point;
}
public IntPtr ControlHandle { get; }
public Point Position { get; }
}
When you click on controls, the click event is eaten by them and doesn't go to the form itself.
To notify the form that one of its controls was clicked, use something like this:
private void control_Click(object sender, EventArgs e)
{
// you control click code here
this.OnClick(new EventArgs());
}
I have parent form called MainBackground and a user control named LoginUI. LoginUI is docked into the MainBackground.
I need to change enability of a button (InfoButton) located in parent form to "true" when user clicks on the button "Log in" in the control form.
But I can't access the parent button's properties.
Control form's button clicking event code:
private void button1_Click(object sender, EventArgs e)
{
MainBackground.infoButton.Enabled = true;
}
I tried solving it with parent controls, but still it doesn't seem to work.
Thanks for any help!
You can't access MainBackground.infoButton from LoginUI because infoButton is not static.
to solve this you could inject MainBackground trough a property like the example below
public partial class LoginUI : UserControl
{
public MainBackground MainBackground { get; set; }
...
}
in MainBackground you should initalize your LoginUI.MainBackground propery
loginUI1.MainBackground = this;
Make sure to make infoButton public
by setting the modifiers property to public
Now you can access MainBackground.loginUI1
private void login_Click(object sender, EventArgs e)
{
MainBackground.InfoButton.Enabled = true;
}
The method described in your question of Enabling the MainBackground forms InfoButton when the Login button is pressed is a common action. However, instead of directly binding the two items where the LoginUI Control is now forever bound to the MainBackground Form, you should de-couple the two by using Events.
The LoginUI Control should publish an event, perhaps called, LoginClicked. The MainBackground form can then subscribe to this event and execute whatever actions are required when the Login button is clicked.
In the LoginUI Control, declare an event:
public event EventHandler LoginClicked;
And, raise it whenever the Login button is pressed:
private void login_Click(object sender, EventArgs e)
{
OnLoginClicked(EventArgs.Empty);
}
protected virtual void OnLoginClicked(EventArgs e)
{
EventHandler handler = LoginClicked;
if (handler != null)
{
handler(this, e);
}
}
Finally, in the MainBackground form class, subscribe to the LoginClicked event
loginUI.LoginClicked += this.loginUI_LoginClicked;
Handle the LoginClicked event like this:
private void loginUI_LoginClicked(object sender, EventArgs e)
{
InfoButton.Enabled = true;
}
Straight to the problem:
In my main form, i have a three buttons that open three different forms. I will show you how it is built.
MainForm (Here is three buttons, with the three different form names on them)
Theory -> Click this button to open TheoryForm
Tasks -> Click this button to open TasksForm
Compete -> Click this button to open CompeteForm
Inside my TasksForm is a button that is going to open the TheoryForm. Here is my code:
public partial class TasksForm : Form
{
public TasksForm()
{
InitializeComponent();
}
public void TheoryButton_Click(object sender, EventArgs e)
{
Form TheoryForm_Child = new TeoriForm();
TheoryForm_Child.Show();
}
//Add some code here so that when `TasksForm` closes, the `TheoryForm_Child` closes too.
}
And what I can't figure out is, when the TasksForm is closed, the TheoryForm is supposed to close as well, right now it doesn't.
Try declaring the variable to your TheoryForm outside of the TheoryButton.Click event handler and then use it in your TaskForm.FormClosing event handler to close it.
public partial class TasksForm : Form
{
private Form TheoryForm_Child;
public TasksForm()
{
InitializeComponent();
FormClosing += TaskForm_FormClosing;
}
public void TheoryButton_Click(object sender, EventArgs e)
{
TheoryForm_Child = new TeoriForm();
TheoryForm_Child.Show();
}
public void TaskForm_FormClosing(object sender, FormClosingEventArgs e)
{
if(TheoryForm_Child != null)
TheoryForm_Child.Close();
}
}
Just because TasksForm is creating TheoryForm does not mean that when TasksForm is closed, so will TheoryForm. Instead, you should close it explicitly like by handing the closed event in your TasksForm, like this.
public partial class TasksForm : Form
{
Form _TheoryFor_Child = new TheoryForm();
public TasksForm()
{
InitializeComponent();
Closed += TasksForm_Closed;
}
private void TasksForm_Closed(object sender, EventArgs e)
{
_TheoryFor_Child.Close();
}
private void TheoryButton_Click(object sender, EventArgs e)
{
_TheoryFor_Child.Show();
}
}
You need to connect parent and child form in some way.
For example in giving the child form the parent form as owner.
Simply call
TheoryForm_Child.Show(this);
There is a really simple solution. You should use the other version of Show method like this:
Form TheoryForm_Child = new TeoriForm();
TheoryForm_Child.Show(this);
That's all. Then your form will be owner of theory form. So it will automagically destroy Theory form after closing itself.
More reading here: https://msdn.microsoft.com/en-us/library/szcefbbd%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
I have a Main Window which includes some User Controls that are initialized in the WPF XAML
MainWindow.xaml.
<Grid>
<local:RegularUnit x:Name="ucRegularUnit" Grid.Row="0" />
<local:Actions x:Name="ucActions" Grid.Row="1" />
// .....
</Grid>
I have a public function in the Main Window which I want to call after clicking a Button in my User Control. After searching for some solutions, I found a way to get the parent window instance in my User Control class, but it can't find the function when I'm using parentWindow.myFunction().
User Control RegularUnit.cs:
public partial class RegularUnit : UserControl
{
public RegularUnit()
{
InitializeComponent();
}
private void Button_SearchSerialNumber_Click(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
//parentWindow. //Can't find the function myFunction()
}
}
MainWindow.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void myFunction()
{
// Do Some Stuff...
}
}
What am I doing wrong, and how can I fix it?
You can't call myFunction on parentWindow because it's not a member of the standard WPF Window class but of your custom MainWindow.
What you could do is to cast the result of Window.GetWindow(this) to MainWindow, like
MainWindow parentWindow = (MainWindow) Window.GetWindow(this);
parentWindow.myFunction();
However this is a really bad class design because now your user control depends on being embedded in a specific window.
What you should rather do is to add an event to the user control on which the parent control can subscribe to.
public event EventHandler SerialNumberSearch;
private void Button_SearchSerialNumber_Click(object sender, RoutedEventArgs e)
{
var handler = SerialNumberSearch;
if (handler != null) handler(this, EventArgs.Empty);
}
Of course you could use a different kind of EventHandler, depending on what you need.
System.Windows.Application.Current.Windows.OfType<YourWindow>().SingleOrDefault(x => x.IsActive).YourPublicMethod();
Although the above code is a messy way of doing it, but it gets the job done nevertheless.
Solution based on event subscription as suggested by Dirk. I have based event on a simple delegate but you can follow similar pattern and base it on a delegate that suits your scenario.
// In UserControl
namespace TextEditor
{
public partial class TextEditorToolBar : UserControl
{
// you can use Action type delegate also
public delegate void getDocumentKeywords();
public event getDocumentKeywords getDocumentRakeKeywordsEvent;
public TextEditorToolBar()
{
InitializeComponent();
}
// This is event handloer for the button on your user control
private void ExtractRakeKeywords(object sender, RoutedEventArgs e)
{
var handler = getDocumentRakeKeywordsEvent;
if (getDocumentRakeKeywordsEvent != null)
getDocumentRakeKeywordsEvent();
}
}
}
// In MainWindow
namespace TextEditor
{
public partial class MainWindow : Window
{
private DocumentKeywordsExtractor KeyWordsExtractor;
public MainWindow()
{
InitializeComponent();
KeyWordsExtractor = new DocumentKeywordsExtractor(richTextBox);
// toolbar is the name given to UserControl in MainWindow.xaml
toolbar.getDocumentRakeKeywordsEvent += ExtractRakeKeywords;
}
private void ExtractRakeKeywords()
{
KeyWordsExtractor.GetRakeKeywords();
}
}