我有一个 WPF 应用程序,它在 ResourceDictionary 中定义了一个NotifyIcon ,该应用程序在 App 启动时添加到 Application.Current.Resources。
我正在使用 MVVM-Light 框架,我想将 NotifyIcon 上的 ContextMenu.MenuItems 的 Command 属性绑定到 ViewModel 中定义的公共 RelayCommand。
我对将 View 耦合到 ViewModel 感到满意,但是如何将 Global Resource 耦合到 ViewModel?
这是我试图让它发挥作用的尝试,只是不确定我是否在正确的路线上......
当我运行此代码时,我收到一条错误消息,指出“找不到名为 'Locator' 的资源。资源名称区分大小写。” 这源于 NotificationIconResources.xaml 中 TaskBarIcon 标记上的 DataContext 绑定
SingleInstanceManager 确保只能创建一个实例
public sealed class SingleInstanceManager : WindowsFormsApplicationBase
{
[STAThread]
public static void Main(string[] args)
{
(new SingleInstanceManager()).Run(args);
}
public SingleInstanceManager()
{
IsSingleInstance = true;
}
public ControllerApp App { get; private set; }
protected override bool OnStartup(StartupEventArgs e)
{
App = new ControllerApp();
App.Run();
return false;
}
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
{
base.OnStartupNextInstance(eventArgs);
App.MainWindow.Activate();
App.ProcessArgs(eventArgs.CommandLine.ToArray(), false);
}
}
ControllerApp 替换 App.xaml 和 App.xaml.cs
public class ControllerApp : Application
{
public MainWindow window { get; private set; }
bool startMinimized = false;
private TaskbarIcon tb;
public ControllerApp()
: base()
{ }
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
DispatcherHelper.Initialize();
ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri("NotificationIconResources.xaml", UriKind.Relative);
Application.Current.Resources.MergedDictionaries.Add(dict);
ViewModel.ViewModelLocator vmLocator = new ViewModel.ViewModelLocator();
Application.Current.Resources.Add("Locator", vmLocator);
window = new MainWindow();
ProcessArgs(e.Args, true);
//initialize NotifyIcon
tb = (TaskbarIcon)FindResource("ItemNotifyIcon");
if (startMinimized)
{
window.WindowState = WindowState.Minimized;
}
window.Show();
}
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
tb.Dispose();
}
public void ProcessArgs(string[] args, bool firstInstance)
{
}
}
NotificationIconResources.xaml 是定义 NotifyIcon 的资源字典
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar">
<tb:TaskbarIcon x:Key="ItemNotifyIcon"
IconSource="/Controller;component/Images/ItemRunning.ico"
IsNoWaitForDoubleClick="True"
ToolTipText="Item is running"
DataContext="{Binding NotifyIcon, Source={StaticResource Locator}}">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu>
<MenuItem Header="Open Control Panel" />
<Separator />
<MenuItem Header="Start Item" Command="{Binding Path=StartServiceCommand}" />
<MenuItem Header="Pause Item" />
<MenuItem Header="Stop Item" Command="{Binding Path=StopServiceCommand}" />
<Separator />
<MenuItem Header="Close" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
</ResourceDictionary>
NotifyIconViewModel 包含我要绑定的 RelayCommands
/// <summary>
/// This class contains properties that the NotifyIcon View can data bind to.
/// <para>
/// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
/// </para>
/// <para>
/// You can also use Blend to data bind with the tool's support.
/// </para>
/// <para>
/// See http://www.galasoft.ch/mvvm/getstarted
/// </para>
/// </summary>
public class NotifyIconViewModel : ViewModelBase
{
private ServiceController sc;
public string Welcome
{
get
{
return "Welcome to MVVM Light";
}
}
/// <summary>
/// Initializes a new instance of the NotifyIconViewModel class.
/// </summary>
public NotifyIconViewModel()
{
if (IsInDesignMode)
{
// Code runs in Blend --> create design time data.
}
else
{
sc = new ServiceController("Item");
}
}
#region Public Commands
private RelayCommand _startServiceCommand = null;
public RelayCommand StartServiceCommand
{
get
{
if (_startServiceCommand == null)
{
_startServiceCommand = new RelayCommand(
() => this.OnStartServiceCommand(),
() => (sc.Status == ServiceControllerStatus.Stopped));
}
return _stopServiceCommand;
}
}
private void OnStartServiceCommand()
{
try
{
sc.Start();
}
catch (Exception ex)
{
// notify user if there is any error
AppMessages.RaiseErrorMessage.Send(ex);
}
}
private RelayCommand _stopServiceCommand = null;
public RelayCommand StopServiceCommand
{
get
{
if (_stopServiceCommand == null)
{
_stopServiceCommand = new RelayCommand(
() => this.OnStopServiceCommand(),
() => (sc.CanStop && sc.Status == ServiceControllerStatus.Running));
}
return _stopServiceCommand;
}
}
private void OnStopServiceCommand()
{
try
{
sc.Stop();
}
catch (Exception ex)
{
// notify user if there is any error
AppMessages.RaiseErrorMessage.Send(ex);
}
}
#endregion
////public override void Cleanup()
////{
//// // Clean up if needed
//// base.Cleanup();
////}
}