C# WPF-将GlobalResource耦合到ViewModel
我有一个在ResourceDictionary中定义的WPF应用程序,该应用程序在应用程序启动时添加到application.Current.Resources 我使用的是MVVM Light框架,我想将NotifyIcon上ContextMenu.MenuItems的命令属性绑定到ViewModel中定义的公共RelayCommand 我很习惯将视图耦合到ViewModel,但如何将全局资源耦合到ViewModel 这是我试图让这个工作,只是不知道我是否在正确的线路上或没有 运行此代码时,我收到一个错误,说明“找不到名为“Locator”的资源。资源名称区分大小写。这源自NotificationIconResources.xaml中TaskBarIcon标记上的DataContext绑定 SingleInstanceManager确保只能创建一个实例C# WPF-将GlobalResource耦合到ViewModel,c#,wpf,mvvm-light,routedcommand,C#,Wpf,Mvvm Light,Routedcommand,我有一个在ResourceDictionary中定义的WPF应用程序,该应用程序在应用程序启动时添加到application.Current.Resources 我使用的是MVVM Light框架,我想将NotifyIcon上ContextMenu.MenuItems的命令属性绑定到ViewModel中定义的公共RelayCommand 我很习惯将视图耦合到ViewModel,但如何将全局资源耦合到ViewModel 这是我试图让这个工作,只是不知道我是否在正确的线路上或没有 运行此代码时,我收
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包含我要绑定到的RelayCommand
/// <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();
////}
}
//
///此类包含NotifyIcon视图可以绑定数据的属性。
///
///使用mvvminpc代码段将可绑定属性添加到此ViewModel。
///
///
///还可以在工具的支持下使用Blend进行数据绑定。
///
///
///看http://www.galasoft.ch/mvvm/getstarted
///
///
公共类NotifyIconViewModel:ViewModelBase
{
私人服务控制器sc;
公众欢迎
{
收到
{
返回“欢迎使用MVVM灯”;
}
}
///
///初始化NotifyIconViewModel类的新实例。
///
public NotifyIconViewModel()
{
如果(IsInDesignMode)
{
//代码在混合-->创建设计时数据中运行。
}
其他的
{
sc=新服务控制器(“项目”);
}
}
#地区公共指挥部
专用中继命令_startServiceCommand=null;
公共中继命令startService命令
{
收到
{
如果(_startServiceCommand==null)
{
_startServiceCommand=新的RelayCommand(
()=>this.OnStartServiceCommand(),
()=>(sc.Status==ServiceControllerStatus.Stopped));
}
返回_stopServiceCommand;
}
}
私有void OnStartServiceCommand()
{
尝试
{
sc.Start();
}
捕获(例外情况除外)
{
//如果有任何错误,请通知用户
AppMessages.RaiseErrorMessage.Send(ex);
}
}
private RelayCommand _stopServiceCommand=null;
公共中继命令StopServiceCommand
{
收到
{
如果(_stopServiceCommand==null)
{
_stopServiceCommand=newrelaycommand(
()=>this.OnStopServiceCommand(),
()=>(sc.CanStop&sc.Status==ServiceControllerStatus.Running));
}
返回_stopServiceCommand;
}
}
私有void OnStopServiceCommand()
{
尝试
{
sc.停止();
}
捕获(例外情况除外)
{
//如果有任何错误,请通知用户
AppMessages.RaiseErrorMessage.Send(ex);
}
}
#端区
////公共覆盖无效清除()
////{
//////如果需要,请清理
////base.Cleanup();
////}
}
鉴于您已经在应用程序级别声明了NotifyIcon,您将无法让它继承另一个视图的ViewModel,因为它不在任何视图的可视树中。最好的办法可能是为NotifyIcon提供自己的ViewModel,并在其上定义命令,然后处理ViewModels之间的通信,而不是跨UI
如果你需要它绑定到一个特定的视图的View模型,你也可以考虑在那个视图中声明它而不是全局的,在这种情况下它可以自动继承你想要使用的DATCONTY文本(但是它将用那个视图打开和关闭)。 我已经解决了这个问题
我从ControllerApp.cs中删除了以下行 ViewModel.ViewModelLocator vmLocator = new ViewModel.ViewModelLocator();
Application.Current.Resources.Add("Locator", vmLocator);
并将ViewModelLocator添加到ResourceDictionary(NotificationIconResources.xaml)中,如下所示
你好,约翰,谢谢你的回复。抱歉-在你回答我的问题时,我一定在补充更多细节。我想我已经做到了,它也遵循了你的建议,但是我被卡住了——你有没有机会回顾一下我刚才添加的代码?
<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"
xmlns:vm="clr-namespace:Controller.ViewModel">
<vm:ViewModelLocator x:Key="Locator"/>
<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="{Binding Path=Item}" />
<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>