Frage

I am trying to implement a notifyicon (http://www.hardcodet.net/projects/wpf-notifyicon) in MVVM project. I understand this control is meant to be used in a regular WPF project.

I am wondering how to implement the ballon feature (Balloon feature). As specified in this tutorial the method "ShowBallonTip" needs to be called

//show balloon with built-in icon
  MyNotifyIcon.ShowBalloonTip(title, text, BalloonIcon.Error);

The only place I could call this method, I can think of, is in the code behind. I do not have a problem with having a little code in a view code behind (even if I would prefer not having any) but I can not figure out how I can have the view model to talk to the view and asks it to call this method.

Even if I place this method in an event how can I raise this event programatically from the viewmodel?

Any idea how I could achieve this?

War es hilfreich?

Lösung

I have been able to display a balloon tip by initialising the icon in the viewmodel instead of the XAML.

Just calling the ShowBalloonTip method in my command do the trick.

I created a wrapper for the notify Icon: NotifyService:

public class NotifyService : INotifyService
{
    private TaskbarIcon icon = new TaskbarIcon
        {
            Name = "NotifyIcon",
            Icon =
                new System.Drawing.Icon(
                    Application.GetResourceStream(Utils.FileUtils.MakeUri("/Icons/email.ico")).Stream),
        };


    public void Notify(string message)
    {

        icon.ShowBalloonTip("title", message, BalloonIcon.None);
    }

    public void ChangeIconSource(string path)
    {
        icon.Icon = new System.Drawing.Icon(
                    Application.GetResourceStream(Utils.FileUtils.MakeUri(path)).Stream);
    }
}

And I used it in my view model: viewmodel

public class MainWindowViewModel : WindowViewModelBase
{
    private readonly INotifyService notifyService = new NotifyService();

    #region Fields
    private static HomeWindowViewModel homeViewModel = new HomeWindowViewModel();
    #endregion
    /// Initializes a new instance of the <see cref="MainWindowViewModel"/> class.
    /// </summary>
    public MainWindowViewModel()
        : base()
    {
        CurrentViewModel = homeViewModel;
    }

    #region Methods

    protected override void OnViewModelPropertyChanged(IViewModel viewModel, string propertyName)
    {
        int t = 2;
    }

    protected override void OnViewModelCommandExecuted(IViewModel viewModel, ICatelCommand command, object commandParameter)
    {
        int t = 2;
        notifyService.ChangeIconSource(@"/Icons/new_email.ico");
        notifyService.Notify("test");
    }
    #endregion
}

Andere Tipps

I found a less obvious solution, but one that arguably fit's better with the MVVM pattern. It allows the TaskbarIcon to be created in XAML and fed new balloon data by the ViewModel.

The first thing to do is add some sort of ability to notify the TaskbarIcon we want it to show a bubble I chose to use Microsofts Rx Extensions (NuGet Package Rx-Main) for this purpouse, but any suitable infrastructure will work. This is the new TaskbarIcon class, and a class for holding the data we would like to pass when the ShowBubbleTip method is called.

using Hardcodet.Wpf.TaskbarNotification;
using System;
using System.Windows;
namespace Phi.Utility
{
    public class TaskbarIconRxBallonNotification
    {
        public Hardcodet.Wpf.TaskbarNotification.BalloonIcon Icon
        {
            get;
            private set;
        }
        public string BallonTitle
        {
            get;
            private set;
        }
        public string Message
        {
            get;
            private set;
        }
        public TaskbarIconRxBallonNotification(Hardcodet.Wpf.TaskbarNotification.BalloonIcon icon, string balloonTitle, string message)
        {
            Icon = icon;
            BallonTitle = balloonTitle;
            Message = message;
        }
    }
    public class TaskbarIconRx : TaskbarIcon
    {
        public IObservable<TaskbarIconRxBallonNotification> BalloonTipNotifier
        {
            get { return (IObservable<TaskbarIconRxBallonNotification>)GetValue(BallonTipNotifierProperty); }
            set { SetValue(BallonTipNotifierProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BalloonSubject.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BallonTipNotifierProperty =
            DependencyProperty.Register("BalloonTipNotifier", typeof(IObservable<TaskbarIconRxBallonNotification>), typeof(TaskbarIconRx), new PropertyMetadata(null, BallonTipNotifierChanged));

        //What to do when we get a new ballonIcon request
        protected void OnNextNotification(TaskbarIconRxBallonNotification notification)
        {
            ShowBalloonTip("", notification.Message, BalloonIcon.Info);
        }
        private IDisposable _subscription;

        //Make sure swapping out bindings doesn't break our program.
        public static void BallonTipNotifierChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TaskbarIconRx currentNotifier = d as TaskbarIconRx;
            if (currentNotifier != null)
            {
                IObservable<TaskbarIconRxBallonNotification> prev = e.OldValue as IObservable<TaskbarIconRxBallonNotification>;
                IObservable<TaskbarIconRxBallonNotification> next = e.NewValue as IObservable<TaskbarIconRxBallonNotification>;

                if (currentNotifier._subscription != null)
                {
                    currentNotifier._subscription.Dispose();
                    currentNotifier._subscription = null;
                }
                if ((next != null))
                {

                    currentNotifier._subscription = next.Subscribe(currentNotifier.OnNextNotification);
                }
            }
        }

    }
}

In our Model, we provide an ISubject to bind to

using System.Reactive.Subjects;
namespace Phi.Models {
    public class SomeModel:ModelBase {
        public ISubject<Utility.TaskbarIconRxBallonNotification> NotifierInterface
        {
            get;
            private set;
        }
        public SomeModel() {
            NotifierInterface = new Subject<Utility.TaskbarIconRxBallonNotification>();

        }
    }
}

In our ViewModel, we can now push notifications through the models subject, like so:

namespace Phi.ViewModels{
    public class SomeViewModel:ViewModelBase
    {
        public SomeModel Model{
            get;
            private set;
        }
        public void PushNotification(string message)
        {
            //Pushes a new notification to the TaskbarIcon.
            Model.NotifierInterface.OnNext(new Utility.TaskbarIconRxBallonNotification(Hardcodet.Wpf.TaskbarNotification.BalloonIcon.Info, "Title", message));
        }
    }
}

and in the XAML, we bind to our models ISubject

<Utility:TaskbarIconRx Visibility= IconSource="/Resources/TinyLogo.ico" BalloonTipNotifier="{Binding Model.NotifierInterface}" >

Simply use a ContentControl in your view bound to a TaskbarIcon object instantiated in your VM. Then issue the commands directly to the object in the VM.

XAML:

     <ContentControl Content="{Binding NotifyIcon}"/>

Code:

    private TaskbarIcon notifyIcon;
    public TaskbarIcon NotifyIcon
    {
        get { return notifyIcon; }
        set { notifyIcon = value; OnPropertyChanged("NotifyIcon"); }
    }
    private void ShowBalloon()
    {
       NotifyIcon.ShowBalloonTip("Hi", "Some info here.", BalloonIcon.Info);
    }
TaskbarIcon MyNotifyIcon = new TaskbarIcon();

    private void ShowStandardBalloon()
    {

        if (ping == false)
        {
            string title = "Website is offline!";
            string text = Url;
            MyNotifyIcon.ShowBalloonTip(title, text, BalloonIcon.Error);
        }else if(ping == true)
        {
            string title = "Website is online!";
            string text = Url;
            MyNotifyIcon.ShowBalloonTip(title, text, BalloonIcon.Info);
        }
     }

Paste this in your ViewModel and change the Values and you'r ready to go. Just call ShowStandartBallon(); and you have no Code in Code Behind.

[EDIT]

TaskbarIcon MyNotifyIcon = new TaskbarIcon();

    private void ShowStandardBalloon()
    {
            string title = "Website is offline!";
            string text = Url; //Url is a String
            MyNotifyIcon.ShowBalloonTip(title, text, BalloonIcon.Error);
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top