Josep B.
Josep B.

Reputation: 587

Onload binding error at runtime in MVVM

I'm trying to use the MVVM Light framework with an "OnLoad" view function, so that when the form is loaded a function from the ViewModel is executed.

I have achieved that, following the examples of several links:

https://stackoverflow.com/a/3409801/2794484 http://aslamhadi.com/add-onload-event-in-wpf-mvvm/ https://social.msdn.microsoft.com/Forums/vstudio/en-US/b4d2afe6-4c28-44e5-98a5-b7ba30fec220/how-to-capture-window-loaded-event-in-view-model-when-using-mvvm?forum=wpf

My view has:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding LoadWindowCommand, Mode=OneWay}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

And my ViewModel:

    public TestViewModel()
    {
        LoadWindowCommand = new RelayCommand(OnLoadWindowCommand);
    }

    public RelayCommand LoadWindowCommand { get; private set; }
    private void OnLoadWindowCommand()
    {
        //put your code here
    }

It works, but using the methods of any of the links, raises me a binding error at runtime:

System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=LoadWindowCommand; DataItem=null; target element is 'EventToCommand' (HashCode=4875788); target property is 'Command' (type 'ICommand')

How can I avoid this error?


Update, I have updated all my code as your recommendations.

MainView:

<Window x:Class="MvvmLight1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:GalaSoft_MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
       xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:ignore="http://www.ignore.com"
        xmlns:local="clr-namespace:MvvmLight1.ViewModel"
        mc:Ignorable="d ignore"
        Title="MVVM Light Application" Height="300" Width="300">
    <Window.Resources>
        <local:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    </Window.Resources>
    <Window.DataContext>
        <!--Move DataContext binding there-->
        <Binding Path="Main" Source="{StaticResource Locator}"/>
    </Window.DataContext>
    <Grid>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Loaded">
                <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding LoadWindowCommand, Mode=OneWay}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Grid>
</Window>

ViewModel:

class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        LoadWindowCommand = new RelayCommand(OnLoadWindowCommand);
    }

    public RelayCommand LoadWindowCommand { get; private set; }
    private void OnLoadWindowCommand()
    {
        Debug.WriteLine("Loaded!");
    }
}

ViewModelLocator

class ViewModelLocator
{
    public ViewModelLocator()
    {
        Main = new MainWindowViewModel();
    }

    public MainWindowViewModel Main { get; private set; }
}

And I have commented the following lines in the App.xaml:

<!--<Application.Resources>
    <vm:ViewModelLocator x:Key="Locator"
                         d:IsDataSource="True" />
</Application.Resources>-->    

But in my "Output" Windows I continue seeing:

....
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=LoadWindowCommand; DataItem=null; target element is 'EventToCommand' (HashCode=44967810); target property is 'Command' (type 'ICommand')
'MvvmLight1.vshost.exe' (Administrado (v4.0.30319)): se cargó 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.Aero\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.Aero.dll', se omitió la carga de símbolos. Se optimizó el módulo y se habilitó la opción 'Solo mi código'.
'MvvmLight1.vshost.exe' (Administrado (v4.0.30319)): se cargó 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationProvider\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationProvider.dll', se omitió la carga de símbolos. Se optimizó el módulo y se habilitó la opción 'Solo mi código'.
'MvvmLight1.vshost.exe' (Administrado (v4.0.30319)): se cargó 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll', se omitió la carga de símbolos. Se optimizó el módulo y se habilitó la opción 'Solo mi código'.
Loaded!

The only difference I can see with your code, is in the namespaces references of the MainWindow:

xmlns:mvvm_light_cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"

And mine:

xmlns:GalaSoft_MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"

If I add your namespace it returns and error trying to resolve "GalaSoft.MvvmLight.Platform"

Any suggestion?

Upvotes: 2

Views: 745

Answers (1)

Anton Danylov
Anton Danylov

Reputation: 1491

Ok, I've got it. Problem is that you are trying to get the Locator resource before it is initialize. Just put your DataContext binding after resources section. Here is the code:

MainWindow.xaml

<Window x:Class="MvvmLight1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:GalaSoft_MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras"
       xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:ignore="http://www.ignore.com"
        xmlns:local="clr-namespace:MvvmLight1.ViewModel"
        mc:Ignorable="d ignore"
        Title="MVVM Light Application" Height="300" Width="300">
    <Window.Resources>
        <local:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    </Window.Resources>
    <Window.DataContext>
        <!--Move DataContext binding there-->
        <Binding Path="Main" Source="{StaticResource Locator}"/>
    </Window.DataContext>
    <Grid>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Loaded">
                <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding LoadWindowCommand, Mode=OneWay}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Grid>
</Window>

MainViewModel.cs

namespace MvvmLight1.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            LoadWindowCommand = new RelayCommand(OnLoadWindowCommand);
        }

        public RelayCommand LoadWindowCommand { get; private set; }
        private void OnLoadWindowCommand()
        {
            Debug.WriteLine("Loaded!");
        }
    }
}

ViewModelLocator.cs

namespace MvvmLight1.ViewModel
{
    public class ViewModelLocator
    {

        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<MainViewModel>();
        }

        public MainViewModel Main
        {
            get
            {
                return ServiceLocator.Current.GetInstance<MainViewModel>();
            }
        }
    }
}

Upvotes: 2

Related Questions