2011-03-31 5 views
1

NotifyIcon이있는 WPF 응용 프로그램은 ResourceDictionary에 정의되어 있으며 응용 프로그램 시작시 Application.Current.Resources에 추가됩니다.WPF - GlobalResource와 ViewModel의 연결

MVVM-Light 프레임 워크를 사용하고 있는데 ViewModel에 정의 된 공용 RelayCommand에 NotifyIcon의 ContextMenu.MenuItems 명령 속성을 바인딩하려고합니다.

뷰를 ViewModel에 연결하는 것이 편하지만 글로벌 리소스를 ViewModel에 연결하는 방법은 무엇입니까? 여기

는이 코드를 실행하면 내가 '라는 이름 리소스를 찾을 수 없습니다 "라는 오류가 발생

이 올바른 라인이나하지 난 경우 그냥 확인 작동 점점에서 내 시도입니다 ... Locator '. 리소스 이름은 대소 문자를 구분합니다. " 이

SingleInstanceManager 단지 하나의 인스턴스가 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) 
    { 

    } 
} 
을 대체
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); 
    } 
} 

을 생성 할 수 있도록 DataContext를가 NotificationIconResources.xaml에 TaskBarIcon 태그에 바인딩에서 유래

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> 
,210

NotifyIconViewModel 난 당신이 응용 프로그램 수준에서 NotifyIcon을 선언 한 점을 감안

/// <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(); 
    ////} 
} 

답변

0

에 결합 할 RelayCommands를 포함, 당신은하지 이후 또 다른 뷰의 뷰 모델을 상속 가질 수 않을거야 모든보기의 시각적 트리에서 최선의 방법은 NotifyIcon에 명령을 정의한 자체 ViewModel을 부여한 다음 UI가 아닌 ViewModel 간의 통신을 처리하는 것입니다.

특정 뷰의 ViewModel에 바인딩해야하는 경우 전역으로보기 대신 해당 뷰를 선언 할 수도 있습니다.이 경우 사용하려는 DataContext를 자동으로 상속받습니다. 그보기로 닫혔다.).

+0

안녕 존처럼 ResourceDictionary에 (NotificationIconResources.xaml)로 응답에 대한 감사를 ViewModelLocator을 추가했습니다. 사과 - 내 질문에 대답하는 동안 더 자세한 정보를 추가 했음에 틀림 없다. 나는 이것이 어딘가에 있다고 생각하지만 당신의 충고를 잘 따르지만 나는 막혔다. 나는 방금 추가 한 코드를 검토 할 수있는 기회가 언제 있을까? – Drammy

0

도움 주셔서 감사합니다.

문제를 해결했습니다.

나는 ControllerApp.cs

ViewModel.ViewModelLocator vmLocator = new ViewModel.ViewModelLocator(); 
    Application.Current.Resources.Add("Locator", vmLocator); 

을에서 다음 줄을 제거하고, 그래서

<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> 
관련 문제