2014-12-21 53 views
4

我想知道如何將NotifyIcon與Caliburn.Micro整合。如何整合WPF NotifyIcon與Caliburn.Micro

我正在嘗試使用低級Caliburn API與Caliburn集成。下面是類:

ITrayIconManager

public interface ITrayIconManager 
{ 
    ITrayIcon GetOrCreateFor<T>(); 
} 

ITrayIcon(包裝紙圍繞TaskbarIconWPF的NotifyIcon

public interface ITrayIcon : IDisposable 
{ 
    void ShowBalloonTip(string title, string message, BalloonIcon symbol); 
    void Show(); 
    void Hide(); 
} 

ISetTrayIconInstance

public interface ISetTrayIconInstance 
{ 
    ITrayIcon Icon { set; } 
} 

TrayIconWrapper

public class TrayIconWrapper : ITrayIcon 
{ 
    private readonly TaskbarIcon icon; 

    public TrayIconWrapper(TaskbarIcon icon) 
    { 
     this.icon = icon; 
    } 

    public bool IsDisposed { get; private set; } 

    public void Dispose() 
    { 
     icon.Dispose(); 
     IsDisposed = true; 
    } 

    public void Show() 
    { 
     icon.Visibility = Visibility.Visible; 
    } 

    public void Hide() 
    { 
     icon.Visibility = Visibility.Collapsed; 
    } 

    public void ShowBalloonTip(string title, string message, BalloonIcon symbol) 
    { 
     icon.ShowBalloonTip(title, message, symbol); 
    } 
} 

TrayIconManager

public class TrayIconManager : ITrayIconManager 
{ 
    private readonly IDictionary<WeakReference, WeakReference> icons; 

    public TrayIconManager() 
    { 
     icons = new Dictionary<WeakReference, WeakReference>(); 
    } 

    public ITrayIcon GetOrCreateFor<T>() 
    { 
     if (!icons.Any(i => i.Key.IsAlive && typeof(T).IsAssignableFrom(i.Key.Target.GetType()))) 
      return Create<T>(); 

     var reference = icons.First(i => i.Key.IsAlive && typeof(T).IsAssignableFrom(i.Key.Target.GetType())).Value; 
     if (!reference.IsAlive) 
      return Create<T>(); 

     var wrapper = (TrayIconWrapper)reference.Target; 
     if (wrapper.IsDisposed) 
      return Create<T>(); 

     return wrapper; 
    } 

    private ITrayIcon Create<T>() 
    { 
     var rootModel = IoC.Get<T>(); 
     var view = ViewLocator.LocateForModel(rootModel, null, null); 
     var icon = view is TaskbarIcon ? (TaskbarIcon)view : new TaskbarIcon(); 
     var wrapper = new TrayIconWrapper(icon); 

     ViewModelBinder.Bind(rootModel, view, null); 
     SetIconInstance(rootModel, wrapper); 
     icons.Add(new WeakReference(rootModel), new WeakReference(wrapper)); 

     return wrapper; 
    } 

    private void SetIconInstance(object rootModel, ITrayIcon icon) 
    { 
     var instance = rootModel as ISetTrayIconInstance; 
     if (instance != null) 
      instance.Icon = icon; 
    } 
} 

這是代碼,現在我該如何使用它?此代碼依賴於卡利視圖 - 視圖模型結合,那就是,我需要創建一個視圖模型爲TasbarkIcon的圖,(其中必須繼承TaskbarIcon控制):

TrayIconViewModel

public class TrayIconViewModel : IMainTrayIcon, ISetTrayIconInstance 
{ 
    public TrayIconViewModel() 
    { 

    } 

    public ITrayIcon Icon { get; set; } 

    public void ShowWindow() 
    { 
     Icon.Hide(); 
     System.Windows.Application.Current.MainWindow.Show(); //very very bad :(
    } 

ITrayIcon是TaskbarIcon控件的包裝。現在我可以從ViewModel調用它,這非常棒。

TrayIconViewCAL:消息:連接不工作 - 的ShowWindow從來沒有被擊中)

<tb:TaskbarIcon x:Class="Communicator.Softphone.Views.TrayIconView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:tb="http://www.hardcodet.net/taskbar" 
      xmlns:cal="http://www.caliburnproject.org" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300" 
      IconSource="/Communicator.ControlLibrary;component/Assets/phone_icon.ico" 
      ToolTipText="Secretária do Futuro - Comunicador" 
      Visibility="Collapsed" 
      cal:Message.Attach="[Event TrayLeftMouseDown] = [Action ShowWindow()]"> 

在我ShellViewModel托盤圖標是TaskbarIcon周圍的包裝):

private ITrayIcon trayIcon; 
protected override void OnActivate() 
    { 
     trayIcon = trayIconManager.GetOrCreateFor<IMainTrayIcon>(); 
     ActivateItem(containers.FirstOfType<IPhone>()); 
    } 
public override void CanClose(Action<bool> callback) 
    { 
     trayIcon.Show(); 
     trayIcon.ShowBalloonTip("Comunicador", "Comunicador foi minimizado", BalloonIcon.Info); 
     (GetView() as Window).Hide(); 
     callback(false); 
    } 

trayIcon.Show()正在工作,但trayIcon.ShowBallonTip(...)不做任何事情,沒有錯誤,沒有什麼。

問題總結

  1. 綁定Message.Attach不工作,雖然這個卡利輸出日誌消息,因爲它是工作。
  2. 調用ShowBallonTip 包裝似乎不工作,雖然它調用實際的TaskbarIcon方法。(它的工作原理沒有附加調試器)
+1

我期待這個。給我一分鐘 – Frank

+0

對不起...我編輯它,使我的情況下:) – JobaDiniz

+0

對不起,但只是問,你可以引用'System.Windows.Forms',如果是的話,你可以直接初始化NotifyIcon查看模型。希望這可能有點幫助。 –

回答

3

完整的答案:

ITrayIcon.cs

裹TaskbarIcon控制,所以你可以呼籲TaskbarIcon方法,而不必在你的視圖模型實際引用。

public interface ITrayIcon : IDisposable 
{ 
    void Show(); 
    void Hide(); 
    void ShowBalloonTip(string title, string message); 
    void ShowBalloonTip(object rootModel, PopupAnimation animation, TimeSpan? timeout = null); 
    void CloseBalloon(); 
} 

ISetTrayIconInstance.cs

public interface ISetTrayIconInstance 
{ 
    ITrayIcon Icon { set; } 
} 

ITrayIconManager.cs

管理TasbarIcon實例。只要你喜歡,你可以擁有儘可能多的TasbarIcon實例。

public interface ITrayIconManager 
{ 
    ITrayIcon GetOrCreateFor<T>(); 
} 

TrayIconWrapper.cs

實現從卡利ViewModelBinder利用。 ShowBallonTip作品一樣IWindowManager.ShowWindow(object rootModel...)呢。它通過ViewLocator實現視圖,將您的rootModel綁定到它,然後傳遞到TaskbarIcon.ShowCustomBallon(UIElement element...

public class TrayIconWrapper : ITrayIcon 
{ 
    private readonly TaskbarIcon icon; 

    public TrayIconWrapper(TaskbarIcon icon) 
    { 
     this.icon = icon; 
    } 

    public bool IsDisposed { get; private set; } 

    public void Dispose() 
    { 
     icon.Dispose(); 
     IsDisposed = true; 
    } 

    public void Show() 
    { 
     icon.Visibility = Visibility.Visible; 
    } 

    public void Hide() 
    { 
     icon.Visibility = Visibility.Collapsed; 
    } 

    public void ShowBalloonTip(string title, string message) 
    { 
     icon.ShowBalloonTip(title, message, BalloonIcon.Info); 
    } 

    public void ShowBalloonTip(object rootModel, PopupAnimation animation, TimeSpan? timeout = null) 
    { 
     var view = ViewLocator.LocateForModel(rootModel, null, null); 
     ViewModelBinder.Bind(rootModel, view, null); 

     icon.ShowCustomBalloon(view, animation, timeout.HasValue ? (int)timeout.Value.TotalMilliseconds : (int?)null); 
    } 

    public void CloseBalloon() 
    { 
     icon.CloseBalloon(); 
    } 
} 

TrayIconManager.cs

我們需要跟蹤的實例化TaskbarIcon年代。這個類是粘合在一起的粘合劑。需要一些TaskbarIcon的實例?詢問TrayIconManager,它會創建一個(如果它尚未創建並且已經存在)並將其返回給您。泛型類型是管理TaskbarIcon實例的視圖模型的類型。

public class TrayIconManager : ITrayIconManager 
{ 
    private readonly IDictionary<WeakReference, WeakReference> icons; 

    public TrayIconManager() 
    { 
     icons = new Dictionary<WeakReference, WeakReference>(); 
    } 

    public ITrayIcon GetOrCreateFor<T>() 
    { 
     if (!icons.Any(i => i.Key.IsAlive && typeof(T).IsAssignableFrom(i.Key.Target.GetType()))) 
      return Create<T>(); 

     var reference = icons.First(i => i.Key.IsAlive && typeof(T).IsAssignableFrom(i.Key.Target.GetType())).Value; 
     if (!reference.IsAlive) 
      return Create<T>(); 

     var wrapper = (TrayIconWrapper)reference.Target; 
     if (wrapper.IsDisposed) 
      return Create<T>(); 

     return wrapper; 
    } 

    private ITrayIcon Create<T>() 
    { 
     var rootModel = IoC.Get<T>(); 
     var view = ViewLocator.LocateForModel(rootModel, null, null); 
     var icon = view is TaskbarIcon ? (TaskbarIcon)view : new TaskbarIcon(); 
     var wrapper = new TrayIconWrapper(icon); 

     ViewModelBinder.Bind(rootModel, view, null); 
     SetIconInstance(rootModel, wrapper); 
     icons.Add(new WeakReference(rootModel), new WeakReference(wrapper)); 

     return wrapper; 
    } 

    private void SetIconInstance(object rootModel, ITrayIcon icon) 
    { 
     var instance = rootModel as ISetTrayIconInstance; 
     if (instance != null) 
      instance.Icon = icon; 
    } 
} 

如何使用

  1. 創建視圖,從TaskbarIcon繼承:

TrayIconView.xaml

<tb:TaskbarIcon x:Class="Communicator.Softphone.Views.TrayIconView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:tb="http://www.hardcodet.net/taskbar" 
      xmlns:cal="http://www.caliburnproject.org" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300" 
      IconSource="/Communicator.ControlLibrary;component/Assets/phone_icon.ico" 
      ToolTipText="Secretária do Futuro - Comunicador" 
      cal:Message.Attach="[Event TrayLeftMouseDown] = [Action ShowWindow()]" 
      TrayLeftMouseDown="TaskbarIcon_TrayLeftMouseDown"> 

  • 創建視圖的視圖模型:
  • TrayIconViewModel.cs

    public class TrayIconViewModel : ISetTrayIconInstance 
    { 
        public TrayIconViewModel() 
        { 
    
        } 
    
        public ITrayIcon Icon { get; set; } 
    
        public void ShowWindow() 
        { 
         System.Windows.Application.Current.MainWindow.Show(); //very very bad :(
        } 
    } 
    
  • 在任何地方通過ITrayIconManager進行Instanciate。例如,在OnActivat方法您ShellViewModel的:

    protected override void OnActivate() 
    { 
        trayIcon = trayIconManager.GetOrCreateFor<TrayIconViewModel>(); 
    } 
    
  • 只要你喜歡使用。舉例來說,在我的ChatManager

    public void NewMessage(IChatMessage message) 
    { 
        trayIcon = trayIconManager.GetOrCreateFor<TrayIconViewModel>(); 
        var notification = new ChatNotificationViewModel(message); 
        trayIcon.ShowBalloonTip(notification, PopupAnimation.Slide, TimeSpan.FromSeconds(5)); 
    } 
    
  • 3

    你可以使用事件聚集,做你想做什麼。

    文檔:http://caliburnmicro.com/documentation/event-aggregator

    添加一個字段,你TaskbarViewModel的事件聚集,並添加一個構造函數,以適應注射:

    public class TaskbarViewModel : PropertyChangedBase, ITaskbar { 
        private readonly IEventAggregator _eventAggregator; 
    
        public TaskbarViewModel(IEventAggregator eventAggregator) { 
         _eventAggregator = eventAggregator; 
        } 
    
        public void Show() { 
         IsVisible = true; 
         _eventAggregator.PublishOnUIThread("Your balloontip message"); 
        } 
    
        /// Rest of the implementation 
    } 
    

    落實IHandle界面,您可以訪問TaskBarIcon並調用ShowBalloonTip方法。

    +0

    我的viewmodel都不能訪問TaskBarIcon ..並且他們應該嗎? TaskBarIcon是一個控件,它是視圖相關的......我可以發佈一個事件,但是誰會聽呢?沒人...我想實現這個的正確方式就像'IWindowManager'如何管理Windows一樣。對此的一些想法會很棒。 – JobaDiniz

    +0

    我從來沒有說過你應該在視圖模型上實現'IHandle'接口。您可以在附加到TaskBarIcon的行爲上實現它。單獨發佈一個事件是沒有用的,這就是爲什麼你需要實現'IHandle'接口並將實現類註冊爲監聽器的原因。 –

    +0

    發佈事件不是方法。我給出的例子非常簡單,但TaskBarIcon還有其他一些功能,如顯示[自定義氣球](http://www.codeproject。com/Articles/36468/WPF-NotifyIcon#氣球)(instanciate,綁定適當的viewmodel-- Caliburn爲我們做的,只需要想一下如何告訴它該綁定什麼)... – JobaDiniz