1

Initially I wanted to pass an "ObservableCollection< customClass>" between two VMs , but even simple messaging isn't working for me.

MainViewModel

 private void openNewSpecialCustomer()
    {
        GalaSoft.MvvmLight.Messaging.Messenger.Default.Send("Musaab");
        Console.WriteLine("send done");
        AddNewSpecialCustomer a = new AddNewSpecialCustomer();
        _dialogService.showDialoge(a);
    }

AddNewSpecialCustomerViewModel

public AddNewSpecialCustomerViewModel()
    {
        GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<string>(this,  doSomething);
        Console.WriteLine("Should now Receive");
        validProperties = new Dictionary<string, bool>();
        validProperties.Add("specialCustomerName",false);
        validProperties.Add("tel", false);
        allPropertiesValid = false;

    }

    public void doSomething(string s)
    {
        Console.WriteLine("Should be received");
        specialCustomerName = s;
        Console.WriteLine("s value " + s);
    }

    public String specialCustomerName
    {
        get { return _specialCustomerName; }
        set
        {
            if (_specialCustomerName != value)
            {
                _specialCustomerName = value;
               OnPropertyChanged("specialCustomerName");

            }
        }
    }

now XAML for AddNewSpecialCustomer

<Window FlowDirection="RightToLeft" x:Class="GlassStore.AddNewSpecialCustomer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:local="clr-namespace:GlassStore.ViewModels"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="AddNewSpecialCustomer" Height="318" Width="458">

<Window.DataContext>
    <local:AddNewSpecialCustomerViewModel/>
</Window.DataContext>
<Grid Background="{DynamicResource NormalBrush}">
    <Button Command="{Binding Save}" Content="موافق" Height="29" HorizontalAlignment="Left" Margin="31,218,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
    <Label Content="إسم العميل" Height="27" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" Width="120" />
    <TextBox Text="{Binding specialCustomerName,Mode=TwoWay,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,UpdateSourceTrigger=PropertyChanged}" Height="27" HorizontalAlignment="Left" Margin="155,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="210" />
    <Label Content="المنطقة/المكان" Height="27" HorizontalAlignment="Left" Margin="12,67,0,0" Name="label2" VerticalAlignment="Top" Width="120" />
    <TextBox Text="{Binding region}" Height="27" HorizontalAlignment="Left" Margin="155,67,0,0" Name="textBox2" VerticalAlignment="Top" Width="210" />
    <TextBox Text="{Binding tel,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,UpdateSourceTrigger=PropertyChanged}" Height="27" HorizontalAlignment="Left" Margin="155,119,0,0" Name="textBox3" VerticalAlignment="Top" Width="210" />
    <Label Content="رقم الهاتف " Height="27" HorizontalAlignment="Left" Margin="12,119,0,0" Name="label3" VerticalAlignment="Top" Width="120" />
    <Button Content="إلغاء" Height="29" HorizontalAlignment="Left" Margin="143,218,0,0" Name="button2" VerticalAlignment="Top" Width="75" />
    <Label Content="" Height="29" HorizontalAlignment="Left" Margin="12,177,0,0" Name="label4" VerticalAlignment="Top" Width="412" />
</Grid>

you can see that there is textBox, with a Text property bounded to specialCustomerName Property , which I'm trying to change it via the messenger , the data-bind mode is TwoWay, so I expect my textBox to have my name on it when loaded , (I'm sending my name via the messenger) which is not the case, I hope this may be more clear code

thanks in advance

Musaab
  • 805
  • 2
  • 13
  • 30

2 Answers2

4

Is your second window constructor called after the first one ? You should first register and only then send the message. Previously sent messages are not received. Sorry for being C.O. but this kind of mistake is rather possible :)

Grigory
  • 1,911
  • 1
  • 16
  • 29
  • yeah , that is what happening , how can I call the constructor then ?? beside this actually works on @Obalix sample blow,what I understood that an event on the first window , when occur I send the message and open the second window then the second VM constructor called,here is where I'm receiving the message , am I missing something here ? – Musaab Jun 26 '11 at 14:03
  • Maybe try to move this line "AddNewSpecialCustomer a = new AddNewSpecialCustomer();" to the position before Messanger.Default.Send in "openNewSpecialCustomer()" method. This will create a Window and a ViewModel before Send method. – Grigory Jun 26 '11 at 14:14
  • Ohh , I can't believe this , it worked now !! , you were right that I have to register first before sending, for @Obalix sample I guess may be I didn't read it well, Thanks alot Mr. Belorus – Musaab Jun 26 '11 at 14:38
  • @Musaab ... this is what I tried to tell you in the first version of my answer ... – AxelEckenberger Jun 26 '11 at 15:57
  • @Obalix yeah I didn't pay attention to "later point in time", I just thought that I had to move from the constructor and braodcast in other place – Musaab Jun 26 '11 at 16:55
  • +1 for pointing out the register first and then send! thanks it helped me! – Overmachine Dec 31 '13 at 15:49
1

As both the sending of the message and the receiving of the message happens in constructors it could lead to a race condition. Register for the receiving of the message in the constructor, but send the message at a later point in time, e.g. in the load or a command handler.

Edit:

Could not reproduce the behaviour, here is the code I used to test this:

ViewLocator:

public class ViewModelLocator
{
    private static MainViewModel _main;

    public ViewModelLocator() {
        CreateMain();
    }

    public static MainViewModel MainStatic {
        get {
            if (_main == null) {
                CreateMain();
            }

            return _main;
        }
    }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
        "CA1822:MarkMembersAsStatic",
        Justification = "This non-static member is needed for data binding purposes.")]
    public MainViewModel Main {
        get {
            return MainStatic;
        }
    }

    public static void ClearMain() {
        if (_main != null) {
            _main.Cleanup();
            _main = null;
        }
    }

    public static void CreateMain() {
        if (_main == null) {
            _main = new MainViewModel();
        }
    }

    #region [SecondViewModel]

    private static SecondViewModel _secondViewModel;

    public static SecondViewModel SecondViewModelStatic {
        get {
            if (_secondViewModel == null) {
                CreateSecondViewModel();
            }

            return _secondViewModel;
        }
    }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
        "CA1822:MarkMembersAsStatic",
        Justification = "This non-static member is needed for data binding purposes.")]
    public SecondViewModel SecondViewModel {
        get {
            return SecondViewModelStatic;
        }
    }

    public static void ClearSecondViewModel() {
        if (_secondViewModel != null) {
            _secondViewModel.Cleanup();
            _secondViewModel = null;
        }
    }

    public static void CreateSecondViewModel() {
        if (_secondViewModel == null) {
            _secondViewModel = new SecondViewModel();
        }
    }

    #endregion

    public static void Cleanup() {
        ClearMain();
        ClearSecondViewModel();
    }
}

MainViewModel

public class MainViewModel : ViewModelBase
{
    public MainViewModel() {
        if (IsInDesignMode) {
            // Code runs in Blend --> create design time data.
        } else {
            // Code runs "for real"
        }
        Messenger.Default.Send("Initializer - does not show becaus of race condition!");
    }

    public string Welcome {
        get {
            return "Welcome to MVVM Light";
        }
    }

    #region [TestCommand]

    private RelayCommand _cmdTest;

    public RelayCommand TestCommand {
        get {
            return _cmdTest ?? (
                _cmdTest = new RelayCommand(
                    () => {
                        // Execute delegate
                        Messenger.Default.Send("Hello!");
                    }
                )
            );
        }
    }

    #endregion

    public override void Cleanup() {
        // Clean up if needed

        base.Cleanup();
    }
}

SecondViewModel

    public SecondViewModel() {
        Messenger.Default.Register<string>(this, (s) => this.DoSomething(s));

        if (IsInDesignMode) {
            // Code runs in Blend --> create design time data.
        } else {
            // Code runs "for real": Connect to service, etc...
        }
    }

    #region [Message]

    public const string MessagePropertyName = "Message";

    private string _message = default(string);

    public string Message {
        get {
            return _message;
        }

        set {
            if (_message == value) {
                return;
            }

            _message = value;

            RaisePropertyChanged(MessagePropertyName);
        }
    }

    #endregion

    public void DoSomething(string s) {
        this.Message = s;
    }

    public override void Cleanup() {
        base.Cleanup();
    }

}

MainWindow XAML

<Window x:Class="MvvmLightTests.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="300"
        Width="300"
        DataContext="{Binding Main, Source={StaticResource Locator}}">

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <StackPanel>
            <StackPanel>
                <TextBlock FontSize="36"
                       FontWeight="Bold"
                       Foreground="Purple"
                       Text="{Binding Welcome}"
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center"
                       TextWrapping="Wrap" />
                <Button Content="click to send message" Margin="0,40,0,0" Command="{Binding TestCommand}" />
            </StackPanel>
            <StackPanel DataContext="{Binding SecondViewModel, Source={StaticResource Locator}}" Margin="0,40,0,0">
                <TextBlock Text="{Binding Message, TargetNullValue='--'}" FontWeight="Bold" HorizontalAlignment="Center"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>
AxelEckenberger
  • 16,628
  • 3
  • 48
  • 70
  • Does it stop if you sent a break point in the doSomething method? Have you implemented the IPropertyChanged interface? Does your test property call RaisePropertyChanged? I tested it yesterday with a command and it worked allright. I post the test later. – AxelEckenberger Jun 26 '11 at 07:25
  • from the edit to the original post you can see that I'm implementing IPropertyChanged interface, RaisePropertyChanged ? , I do have OnPropertyChanged and I believe they do the same thing, then I put 'Console.WriteLine("return " + test);' just after the 'test = s;' in the doSomething() , nothing showed up on the Console ?? – Musaab Jun 26 '11 at 08:14
  • the problem is getting even more weird now, I ran your sample just fine, then I thought maybe because it has only one view, where I have two one for every VM, so I made yours two views and it ran just fine , I know the locator thing has nothing to do with messenger, but I eliminate it too, I ran your sample without the ViewModelLocator class, it rans just fine ??, the only difference I saw between your sample and my project is that I'm using a UserControl where you use a Window, I send then from a VM of a Window and tried to receive from another VM of another Window, failed as usual ?? – Musaab Jun 26 '11 at 12:59
  • I'm going to attach more code, it may help identify the problem – Musaab Jun 26 '11 at 13:01