c# - WPF 从后台线程更新 UI
问题描述
我知道类似的问题已经被问过很多次,但我一直找不到在这种情况下有用的东西。我有一个使用wpf-notifyicon最小化到任务栏的应用程序。主窗口打开、验证然后隐藏。一个进程在后台运行,我希望它将更新发送到主线程。大多数时候它都有效。但是,任务栏图标有一个上下文菜单,允许用户打开应用程序设置。如果我打开然后关闭设置窗口,下次我尝试更新气球时,我会收到空引用错误System.NullReferenceException: 'Object reference not set to an instance of an object.' System.Windows.Application.MainWindow.get returned null.
就像一旦我打开另一个窗口,主窗口就丢失了,我不知道如何再次找到它。
这就是我更新气球的方式。此代码位于通知服务中,可从 MainWindow 视图模型内部和其他服务内部调用。
// Show balloon update on the main thread
Application.Current.Dispatcher.Invoke( new Action( () =>
{
var notifyIcon = ( TaskbarIcon )Application.Current.MainWindow.FindName( "NotifyIcon" );
notifyIcon.ShowBalloonTip( title, message, balloonIcon );
} ), DispatcherPriority.Normal );
通知图标在主窗口的 XAML 中声明。
<tb:TaskbarIcon
x:Name="NotifyIcon"
IconSource="/Resources/Icons/card_16x16.ico"
ToolTipText="Processor"
MenuActivation="LeftOrRightClick"
DoubleClickCommand="{Binding ShowStatusCommand}">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu>
<MenuItem Header="Settings" Command="{Binding ShowSettingsCommand}" />
<Separator />
<MenuItem Header="Exit" Command="{Binding ExitApplicationCommand}" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
<tb:TaskbarIcon.TrayToolTip>
<Border Background="Gray"
BorderBrush="DarkGray"
BorderThickness="1"
CornerRadius="3"
Opacity="0.8"
Width="180"
Height="20">
<TextBlock Text="{Binding ListeningMessage }" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</tb:TaskbarIcon.TrayToolTip>
</tb:TaskbarIcon>
如何从后台线程安全地更新气球图标?
更新1:
上下文菜单绑定到视图模型中的命令。打开设置窗口
<ContextMenu>
<MenuItem Header="Settings" Command="{Binding ShowSettingsCommand}" />
<Separator />
<MenuItem Header="Exit" Command="{Binding ExitApplicationCommand}" />
</ContextMenu>
VM中的命令是:
public ICommand ShowSettingsCommand => new DelegateCommand
{
CommandAction = () =>
{
Application.Current.MainWindow = new Views.SettingsWindow( _logger, _hidservice, _certificateService );
Application.Current.MainWindow.Show();
}
};
要关闭设置窗口,我在后面的窗口代码中有一个动作
public ICommand CancelSettingsCommand => new DelegateCommand
{
CommandAction = () => CloseAction()
};
// In Code Behind
vm.CloseAction = new Action( () => this.Close() );
解决方案
您被覆盖主窗口。你不应该那样做。只需创建它的一个新实例并调用Show()
.
public ICommand ShowSettingsCommand => new DelegateCommand
{
CommandAction = () =>
{
var settingsWindow = = new Views.SettingsWindow( _logger, _hidservice, _certificateService );
settingsWindow.Show();
}
};
推荐阅读
- c++ - 在 std::thread 的移动分配中调用终止
- html - 下拉导航栏在被点击后不会关闭
- ios - 使用 floorf 与 floor
- ios - AngularJS/Material - Simple select-Field not working on ios-devices
- python - 运行 AWS cognito python 脚本的 Eclipse PyDev 错误
- node.js - ExpressJS:意外的 HTTP OPTIONS 请求状态代码 204
- angular - 使用选择标签根据角度的不同选择显示不同的表格
- spring - 使用 PostgreSQL 数据库的特定 SQL 命令进行集成测试
- ascii - ASCII 中的 HTML 数字是如何计算的?
- python - 匹配一个向量和一个矩阵的元素,返回一个新的矩阵