问题
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