deintag
deintag

Reputation: 33

Click-Event from MainWindow.xaml.cs in App.xaml

so i want to outsource some things from MainWindow.xaml to App.xaml like this for example :

<Application x:Class="SVGTesting.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:Type ContentControl}" x:Key="Test1">
                <StackPanel Orientation="Horizontal">
                    <Button Content="Button1" Click="Button_Click" x:Name="Button1"/>
                    <Button Content="Button2" Click="Button_Click" x:Name="Button2"/>
                </StackPanel>
            </DataTemplate>
        </ResourceDictionary>
    </Application.Resources>
</Application>

In MainWindow.xaml then i have something like this

<ContentControl ContentTemplate="{StaticResource Test1}"/>

But now VS says that i cannot use the function "Button_Click" because its not in the codebehind from App.xaml. So how can i call this function from MainWindow in App.xaml?

Is there any way? I don't want answers like MVVM or Command. If it's not possible to solve then WPF is unfortunately useless for me.

Thanks and Greetings.

Upvotes: 0

Views: 2047

Answers (2)

Mikael Koskinen
Mikael Koskinen

Reputation: 12906

This is not the easiest thing to do as WPF expect things to be done in its own way. But there's few options, from easiest to hardest.

1. Don't do anything

Easiest way is to keep your data templates inside the MainWindow.xaml.

2. Use Commands instead of event handlers

You currently have event handlers defined like this:

<Button Content="Button1" Click="Button_Click"

"More-WPF way" of doing this would be to replace Click's event handler with a command with this quite cumbersome syntax:

        <Button Content="Test" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.OnClickCommand}"></Button>

And then define the command in your MainWindow:

    public ICommand OnButtonClick
    {
        get
        {
            return new Command(() =>
            {
                this.Text.Text = "Updated";
            });
        }
    }

3. Define the event handlers in App.xaml.cs and use that to route the event handlers

I don't recommend this as it get tiresome to keep things synced but it's possible. Create and event handler in App.xaml.cs:

public partial class App : Application
{
    private void Button_Click(object sender, RoutedEventArgs e)
    {

    }
}

Then use the sender to access the MainWindow instance and call it's method:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var mainWindow = (MainWindow)Window.GetWindow((DependencyObject)sender);

        mainWindow.DoWork();
    }

In my second example Command is defined like the following:

    public class Command : ICommand
    {
        public delegate void ICommandOnExecute();
        private ICommandOnExecute _execute;

        public event EventHandler CanExecuteChanged;

        public Command(ICommandOnExecute onExecuteMethod)
        {
            _execute = onExecuteMethod;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _execute?.Invoke();
        }
    }

Upvotes: 1

Rekshino
Rekshino

Reputation: 7325

You can't do it. See MSDN documentation for Code-Behind:

The event handlers you write must be instance methods defined by the partial class within the namespace identified by x:Class. You cannot qualify the name of an event handler to instruct a XAML processor to look for that handler in a different class scope. You also cannot use a static method as an event handler.

In WPF you can use a behaviors instead.

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<Button Content="btnWithBehavior">
    <i:Interaction.Behaviors>
        <local:HandleButtonClick/>
    </i:Interaction.Behaviors>
</Button>

public class HandleButtonClick : Behavior<Button>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.Click += AssociatedObject_Click; ;
    }
    private void AssociatedObject_Click(object sender, RoutedEventArgs e)
    {
        //Move your MainWindow.Button_Click here;
    }
    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.Click -= AssociatedObject_Click;
    }
}

Upvotes: 0

Related Questions