Reputation: 16899
I have a UserControl, we'll call it myUC
, that is one among several UserControls in the main window (myWindow
) of my WPF application. myUC
contains a number of standard controls, one of them being a button, we'll call it myButton
.
When I click myButton
, I would like to execute myMethod()
, which exists in the code-behind of myWindow.
The problem being that myUC
doesn't have any idea that myWindow
even exists, much less that myMethod exists.
How can I send the message: 'Hey, myWindow, wake up. myButton on myUc was just clicked; please run myMethod'?
Upvotes: 8
Views: 11485
Reputation: 2814
You can create a command in the window and set the Command property of the button to the name of this command. Clicking the button will fire the command, without a need for a reference to the parent window.
This tutorial explains everything very clearly.
Upvotes: 8
Reputation: 31
The above is all well and good... but seems a bit convoluted to me...
My similar problem: I have a Window (MainWindow.xaml) with a UserControl (SurveyHeader.xaml) in it and inside that UserControl is another UserControl (GetSurveyByID.xaml). I have a private void in MainWindow.xaml that i want to run when a button (btnGetSurvey) is clicked in GetSurveyByID.xaml.
This one line solution worked quite well for me.
this.ucSurveyHeader.ucGetSurveyByID.btnGetSurvey.Click += new RoutedEventHandler(btnGetSurvey_Click);
Upvotes: 3
Reputation: 16899
What I actually ended up having to do in VB:
Create a new Public Class for my custom commands because it was undesirable to have my MainWindow class as Public:
Public Class Commands
Public Shared myCmd As New RoutedCommand
End Class
Create the Execute and CanExecute methods that run the desired code. These two methods were created in the MainWindow code behind:
Class MainWindow
Private Sub myCmdCanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
e.CanExecute = True
e.Handled = True
End Sub
Private Sub myCmdExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
//Do stuff here...
e.Handled = True
End Sub
End Class
Create the Command binding in the MainWindow code-behind and add the two handler methods to the binding (this is the part that is quite different between C# and VB):
Class MainWindow
Public Sub New()
// This call is required by the designer.
InitializeComponent()
//Add any initialization after the InitializeComponent() call.
//Create command bindings.
Dim cb As New CommandBinding(Commands.myCmd)
AddHandler cb.CanExecute, AddressOf myCmdCanExecute
AddHandler cb.Executed, AddressOf myCmdExecuted
Me.CommandBindings.Add(cb)
End Sub
End Class
Add the new custom command to the button object on the UserControl. With a custom command, this did not seem to be possible in XAML, so I had to do it in code-behind. The Commands class needed to be Public so the commands were accessible in this UserControl:
Public Class myUserControl
Public Sub New()
//This call is required by the designer.
InitializeComponent()
// Add any initialization after the InitializeComponent() call.
myButton.Command = Commands.myCmd
End Sub
End Class
Upvotes: 5
Reputation: 286
Try something like this static helper method:
public static T GetParentOfType<T>(DependencyObject currentObject)
where T : DependencyObject
{
// Get the parent of the object in question
DependencyObject parentObject = GetParentObject(currentObject);
if (parentObject == null)
return null;
// if the parent is the type then return
T parent = parentObject as T;
if (parent != null)
{
return parent;
}
else // if not the type, recursively continue up
{
return GetParentOfType<T>(parentObject);
}
}
public static DependencyObject GetParent(DependencyObject currentObject)
{
if (currentObject == null)
return null;
// Convert the object in question to a content element
ContentElement contentEl = currentObject as ContentElement;
if (contentEl != null)
{
// try dependencyobject
DependencyObject parent = System.Windows.ContentOperations.GetParent(contentEl);
if (parent != null)
return parent;
// Convert the contentEl to a FrameworkContentElement
FrameworkContentElement frameworkEl = contentEl as FrameworkContentElement;
// try frameworkcontentelement
if (frameworkEl != null)
return frameworkEl.Parent;
else
return null;
}
// couldn't get the content element, so return the parent of the visual element
return System.Windows.Media.VisualTreeHelper.GetParent(currentObject);
}
Execute it like so:
StaticHelpers.GetParentOfType<Window>(this);
Upvotes: 0
Reputation: 16708
I recommend learning about Routed Events and Routed Commands - this is the sort of thing they're meant to do.
Upvotes: 4
Reputation: 3380
Every control has a parent property which tells you that who actually "owns" this control. You can use that along side with type casting to access your myWindow's myMethod.
You could also use the sender argument of your event handler like this:
(sender as MyWindow).myMethod()
Upvotes: 0