Why can i use Thumb.DragStarted in other controls? [duplicate] - wpf

I will appreciate if some body can explain with a simple example.

Imagine a Window containing a dense hierarchy of child controls. Now let's say you want to do something, there's a right click anywhere in your window.
With normal events, you'd have to handle a Click event for all controls, because you're not sure where the user might click.
With WPF's routed events, the events either "bubble" or "tunnel" (i.e travel up the UI tree or down) if they dont find an event handler, which "handles" it at the current level. So you could write one handler for the window's event i.e. TopLevel. (WPF has a convention of event pairs, PreviewXXX and XXX - the PreviewXXX event fires first and tunnels down from root to control which received the stimulus and the counterpart XXX event then bubbles up from child control back upto Root). So if you right click a button, WPF travels up the UI hierarchy, invoking all handlers that it finds (unless someone marks the event has "handled" in the event args.)

Routed events are events with more 'traveling abilities', as mentioned in a Gishu's answer. Routed events are represented by an instance of a RoutedEvent class + ordinary .NET event, which wraps it:
public class MyClassWithARoutedEvent : UIElement
{
public static readonly RoutedEvent DoSomethingEvent;
public event RoutedEventHandler DoSomething
{
add { base.AddHandler ( MyClassWithARoutedEvent.DoSomethingEvent, value );
remove { base.AddHandler ( MyClassWithARoutedEvent.DoSomethingEvent, value );
}
}
You would typically use touted events in such situations:
Implementing your own control which seamlessly integrates with WPF's infrastructure
Processing events, fired by different controls at a common root
Sort of communication between elements in an element tree
In most situations you will probably use the routed events infrastructure without even noticing it.
In addition it's worth to mention, that you can use RoutedEvent in your control even if it does not define it or even inherits from an element, which does. That's because you can really think about a RoutedEvent instance as a strong typed name of an event. So, if you have an access to this 'name' (this is why an instance of a routed event is usually made public), you can owe it:
public class MyClassWithARoutedEvent : UIElement
{
public static readonly RoutedEvent ClickEvent;
static MyClassWithARoutedEvent ( )
{
ClickEvent = ButtonBase.ClickEvent.AddOwner( typeof ( MyClassWithARoutedEvent ) );
}
// A wrapper should be placed here as described above
}

Related

routed events in multi-instanced user controls wpf

I am building a WPF user control, which generates a SQL WHERE clause 'on the fly', so to speak. That control, in turn, hosts an arbitrary number of another user control, which construct the individual conditions in that WHERE clause.
The instances of this child control contains several comboboxes, a text box (to enter the target value of the condition), and a couple of buttons -- one to add values to a list (e.g., for an 'IN' condition), and one to delete the statement -- and the control which represents it -- entirely.
Here's the issue: When I create an instance of that statement-building control, the control class registers a routed event, which is fired when the user clicks that 'Delete' button; this event is handled by the 'parent' user control, by removing the control from the stack panel that contains the list of 'WHERE' conditions. And it works. Once. If I try to add another instance of that control, it throws an exception: "RoutedEvent Name 'DeleteRule' for OwnerType 'SQLBuilder.ClauseControl' already used."
I've spent the better part of a day Googling, and visiting every StackOverflow reference I found, but nothing deals specifically with the issue of registering routed events by multiple instances of a particular user control.
What am I missing here?
EDIT: Here's the code where I'm registering the event:
public partial class ClauseControl : UserControl
{
// Register the routed event
public readonly RoutedEvent DeleteRule = EventManager.RegisterRoutedEvent("DeleteRule", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(ClauseControl));
public event RoutedEventHandler DeleteRuleEvent
{
add { AddHandler(DeleteRule, value); }
remove { RemoveHandler(DeleteRule, value); }
}
... (Rest of class definition)
Solved it! the RoutedEvent has to be declared 'static'. (At least, that's what worked for me; your mileage may vary.)

auto-wiring a custom event when custom control is double-clicked within design view

Basically, I added a custom event to my TreeView derivative. It is meant to replace the AfterSelected Event, which I disable, because I require a different Event handling mechanism for when people click on tree items.
The event handling itself works well. But I want my new event to be the one wired when a custom control is doubled-clicked in the design view.
The custom class is called CustomTreeView, and this is how it declares its new event.
public event EventHandler CustomSelect;
So basically, when double clicked in the design view, I want this to appear in the MyForm.Designer.cs
this.MyCustomTreeView.CustomSelect += new System.Windows.Forms.TreeViewEventHandler(this.MyCustomTreeView_CustomSelect);
And obviously, the MyCustomTreeView_CustomSelect() function should be added to MyForm.cs
so how do I set this up in my custom control?
You're looking for the DefaultEventAttribute
[DefaultEvent("CustomSelect")]
public class MyCustomTreeView : TreeView
{
//...
}

Communication between user controls in silverlight

I'm pretty new to silverlight so, i'm having this problem about communication between user controls. I have user controls that have buttons in them which are supposed to set some properties of other user controls. For example, IsEnabled property to be set as true or false or visibility, and so on. I actually know one solution which would be something like:
class UserControl1 : Usercontrol
{
public UserControl2 uc2;
private void Button1_Click(object sender, RoutedEventArgs e)
{
uc2.IsEnabled=False; // or uc2.SomeMethod();
}
}
Similar goes for UserControl2 class, and then in main page i only add:
UserControl1.uc2=UserControl2;
My questions is, how can i do this via Event Handlers? Or maybe there is some othe better solution? A simple example would be welcome. Thanks.
Another approach is to use a Event Aggregator for such communication. We in our project are using Prism's event aggregator. Please check the following thread.
Things to keep in mind while using event aggregator are
Keep their usage to minimal. This is because event subscriptions using event aggregator may be difficult to debug. So within the same class use normal events.
Name the events when using event aggregator in a way that describes the event. For example if you click a save button to save customer, use a event name such as BeforeCustomerSave\CustomerSaved instead of SaveButtonClicked.

WPF event that fires after element is fully parented, but before it's arranged

I'm writing a WPF control that dynamically changes its contents depending on what types of Window/UserControl descendants are in its parentage list (part of an experiment with convention vs. configuration).
As such, I need some code to run after my control is fully parented (i.e. all the way up to the Window that's being shown). Ideally, I'd also like my code to run before the first Measure/Arrange pass, since my code is going to change the control's contents and force another Measure/Arrange pass.
I've looked at EndInit, but it fires after the control is loaded from XAML, at which time it might not be fully parented. (For example, if my control was on a UserControl, then EndInit will fire once the UserControl is loaded -- but before it's parented to anything else. I want to wait until the UserControl is parented to something, and that's parented to something else, all the way up.)
Currently I'm just hooking the Loaded event from my control's constructor, and running my code there (oddly enough, WPF doesn't have an OnLoaded method to override):
public class MyControl
{
public MyControl()
{
Loaded += (sender, e) => { ... };
}
}
This works -- it fires when the parents are fully populated -- but it's slightly less than optimal, because there's a Measure/Arrange pass that happens before Loaded.
Is there a good place I can put my code so that it runs after the Parents are set all the way up, but before the first Measure/Arrange pass?
Extra coolness points for solutions that would also work in Silverlight, ElementHost, the Blend/VS designer, and VisualBrush (i.e., not assuming that the top-level parent is a Window, or in the case of VisualBrush, not assuming that there even is a parent -- just that it's as parented as it's gonna be before showing up on the screen, or being sent to the printer, or whatever).
I believe the parents are all set in a single dispatcher operation, so you should be able to get that behavior by putting your logic in a delegate and queuing it up as the next dispatcher operation after the parent is set:
protected override void OnVisualParentChanged(DependencyObject oldParent)
{
base.OnVisualParentChanged(oldParent);
this.Dispatcher.BeginInvoke(new Action(OnReady));
}
private void OnReady()
{
// Element should be fully parented here
}
You could also do that from EndInit rather than OnVisualParentChanged if you want to handle the case of no parent, although EndInit appears to be called more than once so you will need to check for duplicates:
private bool readyQueued;
public override void EndInit()
{
base.EndInit();
if (!readyQueued)
{
this.Dispatcher.BeginInvoke(new Action(OnReady));
readyQueued = true;
}
}
private void OnReady()
{
readyQueued = false;
// Element should be fully parented here
}

When to unhook events in Silverlight

One-line summary: What is the best practice for unhooking event handlers created in the constructor of a UserControl in Silverlight2?
Background:
I am currently building a line-of-business application in Silverlight2. As Silverlight is a browser plugin, there is no concept of a Window - everything is done within UserControls. The way I'm handling different "forms" in the application is to have a top-level usercontrol that contains a Viewbox. To show different forms, I set the Child property of the Viewbox to different UserControls. My app has a singleton PageManager class that is called to open and close forms. The forms (UserControls) are stored in a stack. Opening a form puts it on the top of the stack, closing it removes it from the stack and shows the one below it.
I'm trying to follow the Model-View-ViewModel pattern. In each form (derived from UserControl), I have a ViewModel that manages all the data for the View. The ViewModel exposes events so the UI can be notified when operations such as load and save have completed.
In my form, I subscribe to the event in the constructor, after I've got the ViewModel
public partial class MyPage : UserControl
{
public MyViewModel ViewModel{get; set;}
// other constructors, which create the viewmodel and call the constructor below.
public MyPage(MyViewModel viewModel)
{
InitializeComponent();
ViewModel = viewModel;
this.LayoutRoot.DataContext = this.ViewModel;
// subscribe to event so we can do stuff
this.ViewModel.LoadCompleted += new MyViewModel.LoadCompletedEventHandler(ViewModel_LoadCompleted);
}
My question is: Now that I've subscribed to this event, when do I remove the handler? Do I create a destructor and do it there, or does that create a chicken-and-egg situation where the garbage collector wont destroy the object until all references (ie: the event handlers) are gone? Do I create an interface that the forms must implement that specifies an UnhookEvents function that's called when the form is closed by the PageManager?
Edit: Thanks for the responses. What about the situation where the ViewModel lasts longer than the form (UserControl)? Part of my app allows users to create what is quite a complex structure, but in 95% of cases it's much simpler. What I've did was create 2 forms that use the same ViewModel. Users can start filling out the simple form, then switch to advanced mode, which creates a new form, passing the ViewModel to it.
In the simple setup form:
private void AdvancedSessionSetupButton_Click(object sender, RoutedEventArgs e)
{
PageManager.GetPageManager().Close(this);
PageManager.GetPageManager().Open(new CreateSessionPage(this.ViewModel), "Create Session");
}
In the advanced setup form:
private void BasicSessionSetupButton_Click(object sender, RoutedEventArgs e)
{
PageManager.GetPageManager().Close(this);
PageManager.GetPageManager().Open(new CreateBasicSessionPage(this.ViewModel), "Create Session");
}
After PageManager.Close, the only things referencing the form are the events within the ViewModel. I guess that's where I should be unhooking them.
A destructor, more commonly known to C# programmers as Finalizers, is not necessary in this case. Assuming that ViewModel_LoadCompleted is a member function, it contains a pointer to "this" which you are giving to the ViewModel object which is fully contained by "this". The garbage collector should intelligently ignore this.
In this case, the correct thing to do is to not waste time unbinding them.
In general, you need to unbind an event handler when you pass "this" (explicitly, or implicitly) to some object which will hold that reference longer than the intended lifetime of "this". For example, if you set a handler on a parent control's event. Now the parent has a reference to you via the handler as well as in its Children controls collection. In this case, you should unbind when you are removed from the parent.
When in doubt, implement IDisposable and unbind in the call to Dispose().
Events are automatically unbinded when the garbage collector goes through your object.
But you can explicitly unbind them with the "-=" syntax at anytime:
this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;
You can implement a destructor:
~MyPage
{
this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;
}

Resources