mvvm binding custom event in custom window with viewmodel - c#

I have the following scenario that I am hoping to find a resolution for, I have a custom Window class and I have created an event as below (i have remove some of the code for brevity)
public class AeroWindow : Window
{
public delegate void SystemMenuEventHandler(object sender);
public event SystemMenuEventHandler Exit;
...
public override void OnApplyTemplate()
{
...
var exitButton = this.GetTemplateChild("SM_ExitButton") as Button;
if (exitButton != null)
{
exitButton.Click += (sender, args) => { this.OnExit(); };
}
}
protected virtual void OnExit()
{
if (this.Exit != null)
{
this.Exit(this);
}
}
}
I am using MVVM with Calibutn.Micro and i have a ShellViewModel and ShellView (the ShellView inherits from AeroWindow)
What I would like to know is the following:
How should I correctly create custom events, is the above correct?
How do i then bind to said "event" in the view model
Can the same method of event be used to bubble the events from one view model to another (for example I have the ShellViewModel which initially loads a LoginViewMode (UserControl) and that in turn loads a MainViewModel (UserControl), if I have an event on the Window called Exit can the ShellViewModel subscribe to that and bubble it to the loaded view or should the loaded view subscribe to the window events)
I know that is a number of questions but they are all related to the same thing and I am hoping that someone can provide an answer.

Let me try to answer each of your questions
How should I correctly create custom events, is the above correct?
I think what you did above is correct or you can add an event handler like the usual.
If you're talking about custom events where you will create your own event aside from the built in events of a class, you can actually do that just create a delegate and an event within your class.
How do i then bind to said "event" in the view model
I don't think you want to bind events, what you want to do is to bind commands. You can try to read about ICommand, Relaycommand,
DelegateCommand. You can create an ICommand property in your
viewmodel then bind it to the Command property of the button. There
are also some tools that allows you to bind to events, try to look
for some libraries that offers EventToCommand
Can the same method of event be used to bubble the events from one view model to another (for example I have the ShellViewModel which initially loads a LoginViewMode (UserControl) and that in turn loads a MainViewModel (UserControl), if I have an event on the Window called Exit can the ShellViewModel subscribe to that and bubble it to the loaded view or should the loaded view subscribe to the window events)
In this scenario, where two viewmodel is involved, since you're using caliburn.micro, you might want to check on the
EventAggregator. This will allow you to publish an event from
one viewmodel and subscribe on another viewmodel. Then once the
publish is invoked, all the subscriber will be notified.

Related

What would be the equivalent or closest match of Activated event of Window in Page in WPF?

There is Activated event in a Window in WPF. What is the the closest match for Activated event for a page. I want to use an event that triggers every time a page is displayed.
How about using the IsVisibleChanged event.
In your window, either your base class definition that you use throughout your app, or just the one you are interested in. Add a call at the opening of it something like
public class MyBaseclassWindow : Window
{
public MyBaseclassWindow()
{
IsVisibleChanged += MyBaseclassWindow_IsVisibleChanged;
}
private void MyBaseclassWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// e.NewValue will be TRUE when the visibility is coming back on
if ( !e.NewValue )
return;
// do whatever you want every time window becomes visible.
}
}
If this is something you want done throughout your system, then you can just use THIS window as your base window by always using it as forms are created.
There is the Loaded event which occurs when the element (Page) is laid out, rendered, and ready for interaction.
The Frame class, which I guess is used to host your pages, also has a ContentRendered event that you can handle.

Correct way to pass events from a low level layer to UI? [duplicate]

I have a winform winform1 and 2 user controls control1 and control2 on this form
Now I want to define a custom event, which is raised/fired in control1 and received in control2. The event should be global and not directly defined in control1. control2 should not know about the existence of control1.
The event should also be raised by other controls. How is the C# code for that? Do I need something like a publisher class?
What you describe looks like the Mediator pattern, in which objects communicate through messages. These messages can be implemented as events, callbacks, or any other mechanism.
You could use an implementation like MVVM Light's Messenger class (this framework is intended for use with WPF and Silverlight, but you can get the code for this particular class and use it in WinForms)
// Register for a specific message type
Messenger.Default.Register<TypeOfTheMessage>(this, DoSomething);
...
// Called when someone sends a message of type TypeOfTheMessage
private void DoSomething(TypeOfTheMessage message)
{
// ...
}
// Send a message to all objects registered for this type of message
Messenger.Default.Send(new TypeOfTheMessage(...));
A big advantage of the Messenger class over a static event is that it uses weak references, so it doesn't prevent garbage collection of subscribed objects, which reduces the risk of memory leaks.
See this link for details about the Messenger class
You can use a static event:
public static class MyGlobalEvent {
public static event EventHandler MyEvent;
public static void FireMyEvent(EventArgs args)
{
var evt = MyEvent;
if (evt != null)
evt(args);
}
}
Subscribe in the usual way:
MyGlobalEvent.MyEvent += args => Console.WriteLine("Event Was Fired.");
Fire as you see fit:
MyGlobalEvent.FireMyEvent(new EventArgs());
So you can make your form publisher(and a mediator between controls), and all of your controls will be subscribers that will be notified on event.
An event occurred in a control, form will be notified and event handler on form will notify other controls that subscribed to this event.

Button Trigger an Event Or Command that will be caught by another class

I am trying to trigger an event from a Button that will be caught in a different class without having this class as an instance in my class. Can I do that?
Lets say my Buttons are getting created in PictoPanelViewModel and this class doesnt have any reference to the MainViewModel, I want myButton to trigger an event that will call a method inside MainViewModel.
I tried myButton.Command and myButton.Click but these two need a reference of MainViewModel so I can call it.
I'm a little bit confused now.
EDIT
The Buttons are created dynamically in PictoPanelViewModel
SI assume that MainViewModel has a reference to PictoPanelViewModel at least for an instant, and, to be in the worst case, that the buttons have not been created yet at that time. If this is the case I would:
Add an event myButtonClickedEvn to PictoPanelViewModel
Create a method TriggerMyButtonClickedEvn which simply triggers the event in PictoPanelViewModel
Associate TriggerMyButtonClickedEvn to myButton.Click
In MainViewModel, at the time your class sees PictoPanelViewModel, associate your method to the newly created event.
All this translates in code like this.
In PictoPanelViewModel:
this.myButton.Click += new System.EventHandler(this.TriggerMyButtonClickedEvn);
public event EventHandler myButtonClickedEvn;
private void TriggerMyButtonClickedEvn(object sender, EventArgs e)
{
if (myButtonClickedEvn != null)
myButtonClickedEvn(sender, e);
}
In MainViewModel (in a place where you have the instance of PictoPanelViewModel):
aPictoPanelViewModel.myButtonClickedEvn += new System.EventHandler (myButtonClickedInPictoPanelViewModel);

WPF execute a function before a particular event occurs?

Is there a way to execute a piece of code before an event occurs?
example when we say Expanded="OnExpand"
here the code inside OnExpand occurs after the Expanded event occurs. What if I want to execute a piece of code before that?
You can use the Preview Events
A possible work around for the expander not having a PreviewExpanded event is to handle the PreviewMouseDown event and do a hit test to see if its on the Toggle Button.
Alternatively it may be possible to extend the Expander Class something along the lines of
I did not test this at all no idea is it really works
public class MyExpander: Expander
{
public event EventHandler<EventArgs> PreviewExpanded;
public void OnPreviewExpanded()
{
PreviewExpanded(this,new EventArgs());
}
public override void OnExpanded()
{
PreviewExpanded()
base.OnExpanded();
}
}
If you're talking about the Expander control, you could subclass it and override the IsExpanded property, raising your own PreviewExpanded event before calling base.IsExpanded = value;
If whatever object you are working with supports this behavior it will be in a matching "Preview" event. So, these two events are a before and after matched set.
KeyDown()
PreviewKeyDown()
Expander does not have a preview event for Expanded, if that is what you are working with.

Writing a global custom event in C#

I have a winform winform1 and 2 user controls control1 and control2 on this form
Now I want to define a custom event, which is raised/fired in control1 and received in control2. The event should be global and not directly defined in control1. control2 should not know about the existence of control1.
The event should also be raised by other controls. How is the C# code for that? Do I need something like a publisher class?
What you describe looks like the Mediator pattern, in which objects communicate through messages. These messages can be implemented as events, callbacks, or any other mechanism.
You could use an implementation like MVVM Light's Messenger class (this framework is intended for use with WPF and Silverlight, but you can get the code for this particular class and use it in WinForms)
// Register for a specific message type
Messenger.Default.Register<TypeOfTheMessage>(this, DoSomething);
...
// Called when someone sends a message of type TypeOfTheMessage
private void DoSomething(TypeOfTheMessage message)
{
// ...
}
// Send a message to all objects registered for this type of message
Messenger.Default.Send(new TypeOfTheMessage(...));
A big advantage of the Messenger class over a static event is that it uses weak references, so it doesn't prevent garbage collection of subscribed objects, which reduces the risk of memory leaks.
See this link for details about the Messenger class
You can use a static event:
public static class MyGlobalEvent {
public static event EventHandler MyEvent;
public static void FireMyEvent(EventArgs args)
{
var evt = MyEvent;
if (evt != null)
evt(args);
}
}
Subscribe in the usual way:
MyGlobalEvent.MyEvent += args => Console.WriteLine("Event Was Fired.");
Fire as you see fit:
MyGlobalEvent.FireMyEvent(new EventArgs());
So you can make your form publisher(and a mediator between controls), and all of your controls will be subscribers that will be notified on event.
An event occurred in a control, form will be notified and event handler on form will notify other controls that subscribed to this event.

Categories

Resources