简体   繁体   English

app.xaml.cs与MainViewmodel通讯出现问题

[英]Issue with app.xaml.cs to MainViewmodel communication

I've following code in my wpf App.xaml.cs file: 我在wpf App.xaml.cs文件中遵循以下代码:

 void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            var mainVM = MainWindowViewModel.Instance;
            mainVM.DisplayMessage = string.Format("Something went wrong and it has been logged...If the problem persists, please contact {0}.", mainVM.NotificationsReceiver);
            mainVM.DisplayMessageForegroundColor = "Red";

        e.Handled = true;
    }

MainWindowViewModel.cs MainWindowViewModel.cs

public string DisplayMessage
        {
            get
            {
                return m_displayMessage;
            }
            set
            {
                m_displayMessage = value;
                OnPropertyChanged("DisplayMessage");

            }
        }

        public string DisplayMessageForegroundColor
        {
            get
            {
                return m_displayMessageForegroundColor;
            }
            set
            {
                m_displayMessageForegroundColor = value;
                OnPropertyChanged("DisplayMessageForegroundColor");

            }
        }

MainWindow.xaml MainWindow.xaml

 <Label Content="{Binding DisplayMessage}" Foreground="{Binding DisplayMessageForegroundColor}" Grid.Column="1" HorizontalAlignment="Left" Height="33" Margin="14,660,0,0" Grid.Row="1" 
           VerticalAlignment="Top" Width="693" Grid.ColumnSpan="3"/>

But this does not seem to work.Although the method in app.xaml.cs is getting invoked, I dont see the error getting displayed message on the UI.What could be wrong here please? 但这似乎不起作用。尽管正在调用app.xaml.cs中的方法,但我没有在UI上看到显示消息的错误,请问这里可能出什么问题了? (I'm able to see the message when I set the DisplayMessage and DisplayMessageForegroundColor properties from within MainWindowViewModel though). (不过,从MainWindowViewModel内设置DisplayMessage和DisplayMessageForegroundColor属性时,我可以看到该消息)。

Please advise. 请指教。

Thanks. 谢谢。

The problem is that you wrote a singleton viewmodel, with a singleton Instance , but then you don't use it. 问题是您编写了具有singleton Instance的singleton视图模型,但随后不使用它。 Instead you create a new different instance of the viewmodel in your XAML: 而是在XAML中创建视图模型的新实例:

<Window.DataContext>
    <MainViewModel:MainWindowViewModel />
</Window.DataContext>

That creates a new instance of MainWindowViewModel . 这将创建MainWindowViewModel的新实例。 If your XAML has <TextBox .../> , do you think there's only one TextBox in the world and you're just putting it in a new place? 如果您的XAML具有<TextBox .../> ,您是否认为世界上只有一个TextBox ,您只是将其放在一个新位置? Of course not. 当然不是。 You're creating a new TextBox . 您正在创建一个新的TextBox The same goes for any other XAML element. 其他任何XAML元素也是如此。

The fix is easy: First, remove that Window.DataContext element that I quoted above. 修复很容易:首先,删除我上面引用的Window.DataContext元素。

Then assign the static singleton viewmodel to the DataContext instead: 然后将静态单例视图模型分配给DataContext

<Window
    ...etc...
    xmlns:MainViewModel="clr-namespace:Whatever.Namespace.YourViewModel.IsIn"
    DataContext="{x:Static MainViewModel:MainWindowViewModel.Instance}"
    ...etc...
    >

Or: 要么:

<Window.DataContext>
    <x:StaticExtension 
        Member="MainViewModel:MainWindowViewModel.Instance" />
</Window.DataContext>

<x:StaticExtension ... is the same thing as {x:Static... . <x:StaticExtension ...{x:Static... System.Windows.Markup.StaticExtension is subclass of MarkupExtension . System.Windows.Markup.StaticExtensionMarkupExtension子类。 If one of those has the Extension suffix on the class name, XAML allows you to leave out that part of the name when you use it as a markup extension between curly braces. 如果其中之一在类名上具有Extension后缀,则XAML允许您在将其用作花括号之间的标记扩展名时忽略名称的该部分。 Try this; 尝试这个; it'll work: 它会工作:

DataContext="{x:StaticExtension MainViewModel:MainWindowViewModel.Instance}"

Same thing. 一样。 Binding ( System.Windows.Data.Binding ) is a MarkupExtension as well. BindingSystem.Windows.Data.Binding )也是MarkupExtension That's why you can create one with curly braces in an attribute value in XAML: 因此,您可以在XAML的属性值中使用大括号创建一个:

<TextBox Text="{Binding Foo}" />

Text="{Binding Foo}" creates an instance of System.Windows.Data.Binding . Text="{Binding Foo}"创建System.Windows.Data.Binding的实例。 But Binding doesn't have the Extension suffix on the class name. 但是Binding在类名上没有Extension后缀。 That's not a requirement, it's just a convenience XAML offers if you feel like using it. 这不是必需的,只是XAML提供的便利(如果您想使用它)。

Take-away: Whenever you see Property="{Identifier ...}" in XAML, Identifier is a class derived from System.Windows.Markup.MarkupExtension . 要点:每当在XAML中看到Property="{Identifier ...}"时, Identifier都是派生自System.Windows.Markup.MarkupExtension的类。 Its actual name may be either Identifier or IdentifierExtension , and that curly brace thing is creating and initializing an instance of it. 它的实际名称可能是IdentifierIdentifierExtension ,花括号正在创建和初始化它的实例。

OK, back to your bug. 好,回到您的错误。

Let's learn from it. 让我们从中学习。

When you try to write a singleton class, you need to prevent other classes from creating instances of it, so you don't end up with stuff like this. 当您尝试编写单例类时,需要防止其他类创建它的实例,因此您最终不会遇到这样的事情。 The easiest and best way to do that is to make MainWindowViewModel 's constructor private: 最简单,最好的方法是将MainWindowViewModel的构造函数设为私有:

public class MainWindowViewModel : ViewModelBaseOrWhatever
{
    //  If MainWindowViewModel has no public constructors, no other class can create an 
    //  instance of it. This is a requirement you need to enforce, so and you can make 
    //  the compiler enforce it for you. If you had done this, the compiler would have 
    //  found this bug for you as soon as you wrote it. 
    private MainWindowViewModel()
    {
        //  ...whatever...
    }

    static MainWindowViewModel()
    {
        Instance = new MainWindowViewModel();
    }

    public static MainWindowViewModel Instance { get; private set; }
}

Singletons 单身

On the subject of singleton classes, it's wise to enforce their singleton nature by making the constructor private, and creating Instance in the static constructor: 关于单例类,明智的是通过将构造函数设为私有并在静态构造函数中创建Instance来增强其单例性质:

private MySingletonViewModel()
{
    //  stuff
}

public static MySingletonViewModel Instance { get; private set; }

//  Static constructor
static MySingletonViewModel()
{
    Instance = new MySingletonViewModel();
}

When you do that, the compiler is in on the plan and it won't let you accidentally create a second instance: 当您执行此操作时,编译器已在计划中,它不会让您意外创建第二个实例:

Here, the compiler will complain: 在这里,编译器会抱怨:

'MySingletonViewModel.MySingletonViewModel()' is inaccessible due to its protection level. “ MySingletonViewModel.MySingletonViewModel()”由于其保护级别而无法访问。

The first time you see that you'll say "huh?!", but that's true of most error messages. 第一次看到您会说“嗯?!”,但是大多数错误消息都是如此。

public SomeOtherClass() 
{
    var x = new MySingletonViewModel();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM