使用MVVM-Light的消息传递问题

时间:2011-06-25 18:57:51

标签: wpf mvvm .net-4.0 mvvm-light

最初我想传递一个“ObservableCollection< customClass>”在两个虚拟机之间,但即使是简单的消息也不适用于我。

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");

            }
        }
    }

现在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>

你可以看到有textBox,Text属性被绑定到specialCustomerName属性,我试图通过messenger改变它,数据绑定模式是TwoWay,所以我希望我的textBox上有我的名字它加载时,(我通过信使发送我的名字)但事实并非如此,我希望这可能是更清晰的代码

提前致谢

2 个答案:

答案 0 :(得分:4)

你的第二个窗口构造函数是在第一个之后调用的吗? 您应该首先注册,然后才发送消息。以前发送的消息未收到。很抱歉被C.O.但这种错误很可能:)

答案 1 :(得分:1)

由于发送消息和接收消息都发生在构造函数中,因此可能导致竞争条件。注册在构造函数中接收消息,但稍后发送消息,例如在加载或命令处理程序中。

修改

无法重现行为,以下是我用来测试此代码的代码:

<强> 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>