我在我的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
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
<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"/>
但这似乎不起作用。虽然app.xaml.cs中的方法被调用,但我没有看到错误在UI上显示消息。请问这里有什么问题? (但是当我从MainWindowViewModel中设置DisplayMessage和DisplayMessageForegroundColor属性时,我能够看到该消息。)
请告知。
感谢。
答案 0 :(得分:2)
问题是你用单身Instance
编写了一个单例视图模型,但是你没有使用它。而是在XAML中创建一个新的不同的viewmodel实例:
<Window.DataContext>
<MainViewModel:MainWindowViewModel />
</Window.DataContext>
这会创建MainWindowViewModel
的新实例。如果你的XAML有<TextBox .../>
,你认为世界上只有一个TextBox
并且你只是把它放在一个新的地方吗?当然不是。您正在创建新的TextBox
。任何其他XAML元素也是如此。
修复很简单:首先,删除我上面引用的Window.DataContext
元素。
然后将静态单例视图模型分配给DataContext
:
<Window
...etc...
xmlns:MainViewModel="clr-namespace:Whatever.Namespace.YourViewModel.IsIn"
DataContext="{x:Static MainViewModel:MainWindowViewModel.Instance}"
...etc...
>
或者:
<Window.DataContext>
<x:StaticExtension
Member="MainViewModel:MainWindowViewModel.Instance" />
</Window.DataContext>
<x:StaticExtension ...
与{x:Static...
相同。 System.Windows.Markup.StaticExtension
是MarkupExtension
的子类。如果其中一个在类名上有Extension
后缀,则当您将其用作花括号之间的标记扩展时,XAML允许您省略该部分名称。试试这个;它会工作:
DataContext="{x:StaticExtension MainViewModel:MainWindowViewModel.Instance}"
同样的事情。 Binding
(System.Windows.Data.Binding
)也是MarkupExtension
。这就是为什么你可以在XAML的属性值中用花括号创建一个:
<TextBox Text="{Binding Foo}" />
Text="{Binding Foo}"
创建System.Windows.Data.Binding
的实例。但是Binding
在类名上没有Extension
后缀。这不是一项要求,如果你想使用它,它只是XAML提供的便利。
外卖:当您在XAML中看到Property="{Identifier ...}"
时,Identifier
是从System.Windows.Markup.MarkupExtension
派生的类。它的实际名称可能是Identifier
或IdentifierExtension
,而大括号的东西是创建并初始化它的实例。
好的,回到你的错误。
让我们从中学习。
当你尝试编写一个单例类时,你需要阻止其他类创建它的实例,所以你不会得到这样的东西。最简单,最好的方法是将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; }
}
关于单例类的主题,通过使构造函数私有化并在静态构造函数中创建Instance
来强制执行单例性质是明智的:
private MySingletonViewModel()
{
// stuff
}
public static MySingletonViewModel Instance { get; private set; }
// Static constructor
static MySingletonViewModel()
{
Instance = new MySingletonViewModel();
}
当你这样做时,编译器就在计划中,它不会让你不小心创建第二个实例:
这里,编译器会抱怨:
&#39; MySingletonViewModel.MySingletonViewModel()&#39;由于其保护级别而无法访问。
你第一次看到你说&#34;呵呵?!&#34;,但大多数错误信息都是如此。
public SomeOtherClass()
{
var x = new MySingletonViewModel();
}