1

I have a view, which initializes a viewmodel inside the windows resources. Further more I give my grid the DataContext.

My question is, how I can add a command to my windows closing event keeping mvvm in memory? I tried the version of this post: Handling the window closing event with WPF / MVVM Light Toolkit ... but its not working using an event-trigger, because I can't access the viewmodel from outside my grid, so I can't access my command.

Any solution for my problem?

Greetings

Jannik

Edit: Here's my xaml:

<Window x:Class="WpfApplication1.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:viewModels="clr-namespace:WpfApplication1.ViewModels"
    xmlns:converter="clr-namespace:WpfApplication1.Converter"
    Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <viewModels:MainWindowViewModel x:Key="ViewModel"/>
    </Window.Resources>

    <Grid DataContext="{StaticResource ViewModel}">...</Grid>
</Window>
Community
  • 1
  • 1
Jannik
  • 2,186
  • 4
  • 29
  • 58

2 Answers2

1

You can reference to members of a static resource this way:

Command="{Binding Path=CloseCommand, Source={StaticResource ViewModel}}"

Here's the complete test project. I used a text box with a binding to ensure data is saved.

<Window x:Class="WpfApplication1.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModels="clr-namespace:WpfApplication1.ViewModels"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <viewModels:MainWindowViewModel x:Key="ViewModel"/>
    </Window.Resources>

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Closing">
            <i:InvokeCommandAction Command="{Binding Path=CloseCommand, Source={StaticResource ViewModel}}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <Grid DataContext="{StaticResource ViewModel}">
        <TextBox Text="{Binding Txt, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>

In ViewModel code, I used a static reference to store data (LastInstance). you can replace it with your own method.

Also I used Command which is a custom implementation of ICommand. If you want I can add the complete implementation here.

    public MainWindowViewModel()
    {
        //save or load here...
        if (LastInstance != null) Txt = LastInstance.Txt;
        CloseCommand = new Command(o => LastInstance = this);
        //...
    }

    public static ViewModel LastInstance;

    //Txt Dependency Property
    public string Txt
    {
        get { return (string)GetValue(TxtProperty); }
        set { SetValue(TxtProperty, value); }
    }
    public static readonly DependencyProperty TxtProperty =
        DependencyProperty.Register("Txt", typeof(string), typeof(ViewModel), new UIPropertyMetadata(null));
    //CloseCommand Dependency Property
    public Command CloseCommand
    {
        get { return (Command)GetValue(CloseCommandProperty); }
        set { SetValue(CloseCommandProperty, value); }
    }
    public static readonly DependencyProperty CloseCommandProperty =
        DependencyProperty.Register("CloseCommand", typeof(Command), typeof(ViewModel), new UIPropertyMetadata(null));
Bizhan
  • 15,027
  • 9
  • 55
  • 90
0

The typical approach to this problem is to have a MainViewModel and set the DataContext of you Window to it. Then define other viewModels in the MainViewModel.

<Window>
    <Grid DataContext="{Binding MyGridViewModel}">
    </Grid>
    <DockPanel DataContext="{Binding AnotherViewModel}">
    </DockPanel>
</Window>

in MainWindow constructor:

this.DataContext = new MainViewModel();

in MainViewModel constructor:

this.MyGridViewModel = new OtherViewModel();

This way you have many options to find the desired object through viewModel references.

Bizhan
  • 15,027
  • 9
  • 55
  • 90