Messaging problem using MVVM-Light

六月ゝ 毕业季﹏ 提交于 2020-01-06 03:32:26

问题


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


回答1:


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 :)




回答2:


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>


来源:https://stackoverflow.com/questions/6479860/messaging-problem-using-mvvm-light

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!