繁体   English   中英

如何将WPF NotifyIcon与Caliburn.Micro集成

[英]How to integrate WPF NotifyIcon with Caliburn.Micro

我想知道如何将NotifyIcon与Caliburn.Micro集成。

我正在尝试使用低级Caliburn API与Caliburn集成。 以下是课程:

ITrayIconManager

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

ITrayIcon(TaskbarIcon包装从WPF的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;
    }
}

这是代码,现在我该如何使用它? 此代码依赖于Caliburn View - ViewModel绑定 ,也就是说,我需要为TasbarkIcon和View创建一个ViewModel( 必须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:Message:Attach不起作用 - 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上trayIconTaskbarIcon的包装器):

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不起作用,虽然Caliburn输出日志消息,因为它正在工作。
  2. 虽然它调用实际的TaskbarIcon方法,但在包装器上调用ShowBallonTip似乎不起作用。 (无需附带调试器即可使用)

您可以使用Event Aggregator执行您想要的操作。

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

TaskbarViewModel为Event Aggregator添加一个字段,并添加一个构造函数来容纳注入:

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方法。

完整答案:

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

该实现利用Caliburn 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

我们需要跟踪instanciated TaskbarIcon。 这个类是粘合在一起的粘合剂。 需要一些TaskbarIcon的实例吗? 询问TrayIconManager,它将创建一个(如果它尚未创建并存活)并将其返回给您。 T泛型类型是管理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">

  1. 为视图创建视图模型:

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 :(
    }
}
  1. 通过ITrayIconManager在任何地方实现它。 例如,在ShellViewModelOnActivat方法中:

     protected override void OnActivate() { trayIcon = trayIconManager.GetOrCreateFor<TrayIconViewModel>(); } 
  2. 随时使用。 例如,在我的ChatManager中

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM