Как кнопка может нажать на UserControl выполнить метод в содержащем окне?

у меня есть UserControl, мы назовем его myUC, Это один из нескольких UserControls в главном окне (myWindow) моего приложения WPF. myUC содержит ряд стандартных элементов управления, один из которых является кнопкой, мы назовем его myButton.

когда я нажимаю myButton, Я хотел бы выполнить myMethod(), который существует в коде позади myWindow.

проблемой myUC понятия не имеет, что myWindow даже существует, гораздо меньше, чем myMethod существует.

как я могу отправить сообщение: "Эй, myWindow, проснись. myButton на myUc просто щелкнул; пожалуйста, запустите myMethod'?

6 ответов


вы можете создать команду в окне и задать для свойства команды кнопки имя этой команды. Нажатие кнопки приведет к запуску команды, без необходимости ссылки на родительское окно.

этот учебник объясняет все очень понятно.


что мне на самом деле пришлось делать в VB:

создайте новый открытый класс для моих пользовательских команд, потому что было нежелательно иметь мой класс MainWindow как Public:

Public Class Commands
  Public Shared myCmd As New RoutedCommand
End Class

создайте методы Execute и CanExecute, которые запускают нужный код. Эти два метода были созданы в файл MainWindow код:

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

создайте привязку команды в коде MainWindow и добавьте два метода обработчика к привязке (это часть это совсем другое между C# и 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

добавьте новую пользовательскую команду в объект button на UserControl. С пользовательской командой это казалось невозможным в XAML, поэтому мне пришлось сделать это в коде. Класс Commands должен быть общедоступным, чтобы команды были доступны в этом 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


выше все хорошо... но мне это кажется немного запутанным...

у меня похожая проблема: У меня есть окно (MainWindow.xaml) с UserControl (SurveyHeader.xaml) в нем и внутри этого UserControl является другим UserControl (GetSurveyByID.код XAML.) У меня есть личная пустота в главном окне.xaml, который я хочу запустить при нажатии кнопки (btnGetSurvey) в GetSurveyByID.код XAML.

это решение одной строки работало довольно хорошо для меня.

this.ucSurveyHeader.ucGetSurveyByID.btnGetSurvey.Click += new RoutedEventHandler(btnGetSurvey_Click);

каждый элемент управления имеет родительское свойство, которое говорит вам, кто на самом деле" владеет " этим элементом управления. Вы можете использовать это вместе с литьем типа для доступа к myMethod вашего myWindow.
Вы также можете использовать отправитель аргумент вашего обработчика событий, как это:

(sender as MyWindow).myMethod()

попробуйте что-то вроде этого статический вспомогательный метод:

    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);
    }

выполните его так:

StaticHelpers.GetParentOfType<Window>(this);