I have a button inside my UserControl. I have three instances of this UserControl on the same page.
How can I expose the click event of the button inside such that I can assign different events for each instance of my UserControl.
I think this is similar to concept behind exposing DependencyProperty but I don't understand how to do it for events.
Thanks.
I normally add an event of the same name (and same parameters) to the user control and subscribe to the child control's original event, so I can pass the event on:
public partial class ClickEventControl : UserControl
{
public event EventHandler<RoutedEventArgs> Click;
public ClickEventControl()
{
InitializeComponent();
}
private void aButton_Click(object sender, RoutedEventArgs e)
{
if (Click != null)
{
Click(sender, e);
}
}
}
I would also be interested if there is a more general way of doing it.
Related
In using MVVM pattern, I have a custom inkcanvas with:
protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e)
{
CustomStroke newStroke = new CustomStroke(e.Stroke.StylusPoints, e.Stroke.DrawingAttributes);
this.Strokes.Remove(e.Stroke);
this.Strokes.Add(newStroke);
InkCanvasStrokeCollectedEventArgs eNew = new InkCanvasStrokeCollectedEventArgs(newStroke);
// Raises the System.Windows.Controls.InkCanvas.StrokeCollected event.
base.OnStrokeCollected(eNew);
}
How do I get the view model to receive the InkCanvas.StrokeCollected event?
I can not bind the XAML to the strokes as the StrokeCollection.CollectionChanged event will be called three times by the custom inkcanvas.
Any help is appreciated.
Try this
public Window3()
{
InitializeComponent();
var vm=new ViewModel();
this.DataContext = vm;
canvas.StrokeCollected += vm.OnStrokeCollected;
}
ViewModel
public class ViewModel
{
public void OnStrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
}
}
Edit
if you want to do it without codebehind see the article EventTrigger
You simply bind it via XAML as you already did, which is the correct way to do it.
That you get 3 events, doesn't matter. Just handle the one you need.
For example, if you are only interested in the StrokeCollectedEvent, then just do
protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e)
{
if(e.RoutedEvent != InkCanvas.StrokeCollectedEvent)
return;
// handle the event
}
For a full list of Events, consult the "Fields" Section of InkCanvas MSDN documentation. The fields ending with "Event" are RoutedEvent constants, which are passed in the InkCanvasStrokeCollectedEventArgs.
I've got a usercontrol (MyUC) that is programatically added to a page (MainPage) several times.
In MyUC I set the DataContext to a view model like this:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
DataContext = new MyUCViewModel();
}
In my view model (MyUCViewModel) I have a collection of data items:
public MyDataItemCollection MyDataItems { get; private set; }
And in the constructor I have:
public MyUCViewModel()
{
this.MyDataItems = new MyDataItemCollection();
this.MyDataItems.ChosenItems.CollectionChanged += new NotifyCollectionChangedEventHandler(ChosenItemsChanged);
this.MyDataItems.Add(new DataItem());
}
From the above MyDataItems has another collection in it for ChosenItems and I added a NotifyCollectionChangedEventHandler to it.
Other parts of my code add and remove from the ChosenItems collection and that part seems to work ok.
Next I have the event handler method in the view model:
private void ChosenItemsChanged(object sender, EventArgs e)
{
MessageBox.Show("Chosen Items Changed");
}
This also works and I get a messagebox everytime the user makes a change in the UI that affects the ChosenItems collection.
The part I'm trying to figure out now is how do I set it up so that my MainPage does something when the ChosenItemsChanged event fires in my user controls. What I want to do is have the MainPage loop through the generated MyUC controls on the page and make each usercontrol call a method.
You can add more event listeners in the MainPage like this:
MyUCViewModel viewModel = myUC.DataContext;
viewModel.MyDataItems.ChosenItems.CollectionChanged
+= new NotifyCollectionChangedEventHandler(MainPage_ChosenItemsChanged);
This is based on the comment as the question was a little misleading:
While not strictly MVVM, as your question appears to be, your should write your User Controls as if it was a third-party control and simply expose a custom event on it. User Controls should always be a black-box with a public interface. For a reusable control that is self-contained (as many are) MVVM is overkill.
e.g.
in your User Control add:
public event EventHandler<MyEventArgs> MyEvent
Create a MyEventArgs class deriving from EventArgs and get it to hold useful parameters (like the selected item).
In your main page add a handler to MyEvent on each User Control you dynamically add.
I actually think the MVVM model is flawed and all this sort of controlling logic and event handlers belong in a Controller class (MVCVM!), but that's another story. :)
I am trying to understand how RoutedEvents work.
Well - I walked through some tutorials and understood why RoutedEvents are useful and how they work.
But there is one thing, that I don't get:
Let's say I wrote a class (e.g. "MyClass") , which has a RoutedEvent property, sth. like this:
public class MyClass
{
public static readonly RoutedEvent myEvent;
...
}
Well - just giving a property is not enough - so I have to register the RoutedEvent with the help of EventManager:
...
myEvent = EventManager.RegisterRoutedEvent("MyEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyClass));
...
Okay - now the WPF event system knows about THIS event.
If I do it that way, each class I write will have it's own RoutedEvent. But that makes no sense to me.
What I want, is that other classes listen to the same event - without being a type of MyClass.
For example:
I have a stackpanel and within the stackpanel is a button. Clicking the stackpanel will raise the onClick event. Clicking the button will raise the onClick event of the button - and then the onClick event on the stackpanel.
But how?
Sorry - it's hard for me to describe the problem - I am just too confused :)
Thx a lot.
CodeCannibal
What I want, is that other classes listen to the same event - without being a type of MyClass.
You expect the right from this and this is what it delivers. I mean by registering a RoutedEvent you are not strongly binding it to the type; instead you are bridging it using the string "MyEvent" EventManager.RegisterRoutedEvent("MyEvent", ...
RoutedEvent traverse through the logical tree and stops traversing when handled (exceptions are there).
So, StackPanel need not to be derived from MyClass. You just need to register the RoutedEvent at StackPanel by specifying the action/handler. Whenever the RoutedEvent traverse through StackPanel it will call the corresponding action.
For example:
UserControl1.cs
//Routed Event
public static readonly RoutedEvent ThisIsEvent = EventManager.RegisterRoutedEvent("ThisIs", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(UserControl1));
// .NET wrapper
public event RoutedEventHandler ThisIs
{
add { AddHandler(ThisIsEvent, value); }
remove { RemoveHandler(ThisIsEvent, value); }
}
//local handler where RaiseEvent is called
private void button1_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ThisIsEvent));
}
And below is how you subscribe to that event in you XAML. You can also do this in your code file...
<StackPanel Orientation="Vertical" **local:UserControl1.ThisIs="StackPanel_ThisIs"** >
<local:UserControl1></local:UserControl1>
</StackPanel>
I hope this clear your doubts.
I have a UserControl in my WPF application.
I want to call a click event and do some things when the user clicked the UserControl.
The problem is- the UserControl doesn't have a click event.
I searched on the web and found that you can use the MouseLeftButtonUp event.
I tried it- but it doesn't respond to my clicks.
You didn't write what you are trying to do but if you need a click event maybe you are writing some kind of button (the Button class is actually "something you can click" with the visual representation in a control template you can replace)
If you need a button with complex content inside - put your user control inside a button
If you need a button that doesn't look like a button write a custom control template for button
If you need a button with extra functionality subclass button, add the extra data/behavior in code and put the display XAML in a style.
I think for your needs PreviewMouseLeftButtonUp(Down) event is more suitable. Then you need to handle ClickCount for counting amount of clicks and then raise your own event, on which other controls will know, that your control is clicked. There are much more methods on handling click event. You should look at this msdn article and this
UPDATE to handle both Click and DoubleClick
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_myCustomUserControl.MouseLeftButtonUp += new MouseButtonEventHandler(_myCustomUserControl_MouseLeftButtonUp);
_myCustomUserControl.MouseDoubleClick += new MouseButtonEventHandler(_myCustomUserControl_MouseDoubleClick);
}
bool _doubleClicked;
void _myCustomUserControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
_textBlock.Text = "Mouse left button clicked twice";
_doubleClicked = true;
e.Handled = true;
}
void _myCustomUserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_doubleClicked)
{
_doubleClicked = false;
return;
}
_textBlock.Text = "Mouse left button clicked once";
e.Handled = true;
}
}
To test this example name your control as _myCustomUserControl and add a TextBlock named _textBlock to your MainWindow.xaml
Why not just use MouseDown?
Put the event in the User Control and simply do this:
private void MyControl_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
MessageBox.Show("Clicked!");
}
}
I have a WPF Custom Control inherited from Button.
How do I programatically get the custom control to capture the Click Event (so that I can record the action and do some internal work)
(basically I want to catch the event and set a certain property to a certain value) and make this part of the classes standard functionality.
From my understanding the custom control should be able to catch it's own even and do some work.
Help appreciated
try one of the overrides
public class CustomButton : Button {
protected override void OnPreviewMouseDown(MouseButtonEventArgs e) {
base.OnPreviewMouseDown(e);
}
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) {
base.OnPreviewMouseLeftButtonDown(e);
}
}
I have realised why Ihad a problem.
I could not see the Click event
This was because I was not explicit enought in my class declaration:
I put
public class StateButton : Button
obviously picked the wrong button .. as
public class StateButton : System.Windows.Controls.Button
works
Then I just override the event
Thanks