I have a very interesting task that I need help with. The description is as follows:
I have a user control (SomeUserControl), that I am using in a Main Window. I write my application entirely on SomeUserControl, and Main Window is hosting SomeUserControl and nothing else.
Right now I have a shutdown button (in SomeUserControl), that is supposed to close the Main Window. The reason for this is that I do not want anything from SomeUserControl to close the application itself, but to fire an event from SomeUserControl, and Main Window receives it, and Main Window will close the application instead of SomeUserControl.
How do I do it? I am not familiar with the concept of creating and handling custom events, so if someone could explain it in words and in code as an example, I will be very grateful to you!
Edit: Here's my code so far.
(in Window 2)
Public Event CloseApp As EventHandler
Private Sub CancelButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles CancelButton.Click
DialogResult = False
RaiseEvent CloseApp(Me, New EventArgs)
End Sub
(In Main Window)
Public loginPage As New LoginPage
Public Sub New()
InitializeComponent()
AddHandler loginPage.CloseApp, AddressOf Me.ShutDownJobChangeWindow
End Sub
Private Sub ShutDownJobChangeWindow(ByVal sender As Object, ByVal e As EventArgs)
Application.Current.Shutdown()
End Sub
Goal: I want to close the application when I click cancel in Window 2, but I don't want to do it in such a way that Window 2 closes itself, but by sending some notification to Main Window, and Main Window closes the application.
If the logic of the user control is implemented in the "code behind" of the user control class, do the following.
I'm assuming the XAML file has somewhere a button with a click event:
<Button Click="Button_Click">Close App</Button>
Then, in your code behind for SomeUserControl class, do the following:
public partial class SomeUserControl : UserControl
{
public event EventHandler CloseApp;
...
private void Button_Click( object sender, RoutedEventArgs e )
{
if( CloseApp != null ) {
CloseApp( this, new EventArgs( ) );
}
}
}
In your Main window, listen to the event:
...
someUserCtrl.CloseApp += new EventHandler( MyFn );
private void MyFn( object sender, object EventArgs e ) {
...
}
The simplest way to do this is to declare a custom event:
public delegate void ShutdownEventHandler (object sender, EventArgs data);
public event ShutdownEventHandler Shutdown;
protected void OnShutdown(EventArgs args)
{
if(Shutdown != null)
Shutdown(this, args);
}
Then you subscribe to the Shutdown event in MainWindow, and handle shutdown logic there.
And in SomeUserControl, you simply run OnShutdown when you want to shutdown your application.
I had the same problem, and I've solved in this way:
if you are using a soft version of MVVM (with soft I mean that you use codebehind for events handling) and your event is within the ModelView class do this:
In your MainWindow:
public MainWindow(ViewModels.MyViewModel vm)
{
InitializeComponent();
//pass the istance of your ViewModel to the MainWindow (for MVVM patter)
this.vm = vm;
//Now pass it to your User Control
myUserControl.vm = vm;
}
In your UserControl
public partial class MyUserControl: UserControl
{
public ViewModels.MyViewModel vm;
public MyUserControl()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
vm.MyMethod();
}
}
Last but not least, in your MainWindow's xaml insert your user control and give it a name:
<local:MyUserControl x:Name="myUserControl" />
If you don't want to use a ViewModel, you can simply pass to your UserControl an instance of your MainWindow and then you can run within the codebehind of your usercontrol all of your MainWindow's public methods.
Hope it will help!
Sorry, the question is VB so here is the VB version of the code above:
MainWindow:
Public Sub New(ByVal vm As ViewModels.MyViewModel)
InitializeComponent()
Me.vm = vm
myUserControl.vm = vm
End Sub
UserControl:
Public Partial Class MyUserControl
Inherits UserControl
Public vm As ViewModels.MyViewModel
Public Sub New()
InitializeComponent()
End Sub
Private Sub button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
vm.MyMethod()
End Sub
End Class
Related
im trying to learn how to use WPF data binding.
I have a control, and i want to change the value f a property in the control.
<somecontrol Value="{Binding GoodRange}">
I created the property in the MainWindow Class as follows:
Public Property GoodRange As Double
Get
Return m_GoodRange
End Get
Set(value As Double)
m_GoodRange = value
End Set
End Property
Private m_GoodRange As Double
Inside the Mainwindow class i added the following to the sub New()
Public Sub New()
InitializeComponent()
GoodRange = 3000
Me.DataContext = Me
End Sub
So far so good, hwen i launch the program the value 3000 is passed to the control.
Now, during runtime i want to change the property for example when a user clicks on a button, or on a timed event eg:
Private Sub UpdateValue()
GoodRange = 2800
End Sub
When i do this, the value on the control is not updated. im trying to understand how i can trigger the control to update.
I have googled for 4 hours try try and understand, and i have found and tried a lot of answers on google, but usually these answers are for custom controls or custom classes or using the .datacontex method which i cant use as multiple property's will need to be changed.
I would be greatfull for any help you guys can offer.
Thank you/
As Clemens says in the comment to your question, you really need to do some research on MVVM, which has Data Binding as its heart and soul. An excellent article to start is of course the classic from Josh Smith, MVVM Design Pattern
In the meantime, as a minimum functional example, you should create a class as shown below that implements the INotifyPropertyChanged interface (code below is in C#):
public class myViewModel : INotifyPropertyChanged
{
private double goodRange = 3000;
public double GoodRange
{
get
{
return goodRange;
}
set
{
if (value != goodRange)
{
goodRange = value;
NotifyPropertyChanged("GoodRange");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In the code behind of your window:
Dim mVM as myViewModel
Public Sub New()
InitializeComponent()
mVM = new myViewModel()
Me.DataContext = mVM
End Sub
Private Sub UpdateValue()
mVM.GoodRange = 2800
End Sub
I want to show firstly my login form (FrmLogin) and if user correctly put his credentials to close FrmLogin and show main form (FrmMain) therefore i did following steps:
in Application.xaml instead of StartupUri i placed:
Startup="Application_Startup">
then in Application.xaml.vb:
Class Application
Private Sub Application_Startup(sender As Object, e As StartupEventArgs)
Dim result As New FrmLogin
result.ShowDialog()
If (result.DialogResult.HasValue And result.DialogResult.Value) Then
Dim FrmMain As New FrmMain()
Run(FrmMain)
Else
MessageBox.Show("User clicked Cancel")
'closing application...
End If
End Sub
End Class
in FrmLogin:
Public Class FrmLogin
Private Sub btnOk_Click(sender As Object, e As RoutedEventArgs) Handles btnOk.Click
Me.DialogResult = True
End Sub
Private Sub btnCancel_Click(sender As Object, e As RoutedEventArgs) Handles btnCancel.Click
Me.DialogResult = False
End Sub
End Class
unfortunetly i got errors on those lines in Applciation_Startup:
Dim FrmMain As New FrmMain()
Run(FrmMain)
error message:
Additional information: Application is already running the Dispatcher.
what i am doing wrong and what should i do? By the way is this approach correct?
I have done this in the Past and the way I accomplished this is as follows:
Modify App.xaml C# or Application.xaml VB:
<Application x:Class="LoginFormExample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LoginFormExample"
StartupUri="winMDI.xaml" ShutdownMode="OnExplicitShutdown" Startup="Application_Startup" >
<Application.Resources>
</Application.Resources>
The Key Piece is ShutdownMode="OnExplicitShutdown" which prevents the program from shutting down after the first window is closed, which would be your Login Window.
Next modify the App.xaml.cs like this:
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
winLogin login = new winLogin();
bool? bResult = login.ShowDialog();
if (!bResult.HasValue || !bResult.Value)
{
MessageBox.Show("Failed Login");
this.Shutdown();
}
}
}
or Application.xaml.vb:
Class Application
Private Sub Application_Startup(sender As Object, e As StartupEventArgs)
Dim login As New winLogin()
Dim bResult As Nullable(Of Boolean) = login.ShowDialog()
If Not bResult.HasValue OrElse Not bResult.Value Then
MessageBox.Show("Failed Login")
Shutdown()
End If
End Sub
End Class
And Last since ShutdownMode="OnExplicitShutdown" you will need to shutdown your app after your main window closes manually like this:
<Window x:Class="LoginFormExample.winMDI"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:LoginFormExample"
mc:Ignorable="d"
Title="winMDI" Height="300" Width="300" Closed="Window_Closed">
<Grid>
</Grid>
Key Piece = Closed="Window_Closed"
And:
C#
public partial class winMDI : Window
{
public winMDI()
{
InitializeComponent();
}
private void Window_Closed(object sender, EventArgs e)
{
Application.Current.Shutdown();
}
}
VB
Class winMDI
Private Sub Window_Closed(sender As Object, e As EventArgs)
Application.Current.Shutdown()
End Sub
End Class
Hope that helps.
you can also try set FrmLogin.xaml as startup window.
StartupUri="FrmLogin.xaml"
in FrmLogin, after login succeed, create new MainWindow and Show(), then close FrmLogin.
I have a custom menu control in the main window of my WPF application. In main window, I have a frame. I want to change the page in this frame based on the selection in the custom menu control. Below is the code I tried.
Private Sub NominationMenuItem_Click(sender As Object, e As RoutedEventArgs)
Dim parentWindow As Window
parentWindow = Application.Current.MainWindow
parentWindow.MainFrame.Navigate(New NominationSearch)
End Sub
I know that I can't directly access "MainFrame" control using the "parentWindow" object. How do I rewrite the last line to get a reference to the existing frame object.
It's not appropriate for UserControl to manipulate it's parent. You should let your MainWindow to listen for NominationMenuItem changes via events and then MainWindow itself do the navigation.
So first you need to define an event in your UserControl:
Public Event NominationMenuItemChanged As RoutedEventHandler
Private Sub NominationMenuItem_Click(sender As Object, e As RoutedEventArgs)
RaiseEvent NominationMenuItemChanged(Me, New RoutedEventArgs())
End Sub
And then listen to this event in your MainWindow:
Public Sub MainWindow()
AddHandler MyUserControl.NominationMenuItemChanged, AddressOf UC_NominationMenuItemChanged
End Sub
Private Sub UC_NominationMenuItemChanged(sender As Object, e As RoutedEventArgs)
MainFrame.Navigate(MyUserControl.NominationSearch)
End Sub
I want to have an image (or a button) that, when the user click on it, it closes the window, like ALT+F4.
Okay...this is an extremely simple operation.
For a Button, handle the Click() event and Close() the Form. You can simply double click the Button to have the method stub inserted for you. The exact same thing can be done with a PictureBox:
VB.Net:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Close()
End Sub
Private Sub PictureBox1_Click(sender As Object, e As EventArgs) Handles PictureBox1.Click
Me.Close()
End Sub
End Class
C#:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
private void pictureBox1_Click(object sender, EventArgs e)
{
this.Close();
}
}
I have a winform with a wpf usercontrol on it (ElementHost1). The usercontrol contains only a button. How can I know when the wpf button has been clicked in my winform? How can I "redirect" the events from wpf usercontrol to winform?
Thanks.
This link might be helpful to you.
Or a simple event handling in VB.NET
Public Event ClickMe()
Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
RaiseEvent ClickMe()
End Sub
Then in your actual window you can have this:
Public Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
AddHandler SampleClick1.ClickMe, AddressOf Sample_Click
End Sub
Private Sub Sample_Click()
MessageBox.Show("This is a proof!")
End Sub
That SampleClick1 variable is from the designer code generated available to the form for your use.
Friend WithEvents ElementHost1 As System.Windows.Forms.Integration.ElementHost
Friend SampleClick1 As WindowsApplication1.SampleClick
Here is the one solution i found
in UserControl1.Xaml.cs
public static RoutedEvent ChkBoxChecked = EventManager.RegisterRoutedEvent("CbChecked", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(CheckBox));
public event RoutedEventHandler CbChecked
{
add
{
AddHandler(ChkBoxChecked, value);
}
remove
{
RemoveHandler(ChkBoxChecked, value);
}
}
private void cbTreeView_Checked(object sender, RoutedEventArgs e)
{
RoutedEventArgs args = new RoutedEventArgs(ChkBoxChecked);
RaiseEvent(args);
}
Now in MainForm Form1 shown event we can add CbChecked event
private void Form1_Shown(object sender, EventArgs e)
{
this.elemetHost1.CbChecked += new System.Windows.RoutedEventHandler(wpfusercontrol_CbChecked);
//elementHost1 is the name of wpf usercontrol hosted in Winform
}
void elementHost1_CbChecked(object sender, System.Windows.RoutedEventArgs e)
{
//This event will raise when user clicks on chekbox
}
i am facing an issue here.i am rasing the same event in Form1 for all checkbox clickevents in UserControl1.so i want to know which checkbox is clicked in the mainform.i tried to see in the RoutedEventArgs e....but doesnt help
how to know which checkbox is clicked in the mainform