简体   繁体   English

C#MVVM使用NotifyIcon从代码背后调用ViewModel方法

[英]C# MVVM Calling ViewModel method from Code Behind using NotifyIcon

I can't seem to get a method in my ViewModel to run successfully from my XAML code behind when using NotifyIcon. 使用NotifyIcon时,似乎无法从我的XAML代码中成功运行ViewModel中的方法。 The method executes correctly, as tested with debugging mode using breakpoints, but nothing happens in the View. 该方法可以正确执行,如使用断点的调试模式所测试的那样,但是在View中什么也没有发生。

The method in question is RefreshData, and it can be called from either a button in the View (works as expected), or from right clicking the NotifyIcon and selecting Refresh Data (does nothing). 有问题的方法是RefreshData,可以从“视图”中的按钮调用(按预期方式工作),也可以通过右键单击NotifyIcon并选择“刷新数据”来调用它(不执行任何操作)。 I'll post relevant code below. 我将在下面发布相关代码。 Any help would be appreciated! 任何帮助,将不胜感激!

MainWindow constructor in CodeBehind CodeBehind中的MainWindow构造函数

public MainWindow()
    {
        try
        {
            MM = new MMViewModel();
            InitializeComponent();                
            DataContext = MM;

            _notifyIcon = new NotifyIcon();
            _notifyIcon.DoubleClick += (s, args) => ShowMainWindow(this);
            _notifyIcon.Icon = Migration_Monitor_v2.Properties.Resources.mmc;
            _notifyIcon.Visible = true;

            Closing += MainWindow_Closing;

            CreateContextMenu();
        }
        catch (Exception e)
        {
            logger.Error("App failed with exception: ", e);
        }
    }

    private void CreateContextMenu()
    {
        _notifyIcon.ContextMenuStrip = new ContextMenuStrip();
        _notifyIcon.ContextMenuStrip.Items.Add("Refresh Data").Click += (s,e) => MM.RefreshData();
        _notifyIcon.ContextMenuStrip.Items.Add("Exit").Click += (s, e) => ExitApplication(this);
    }

RefreshData method in ViewModel (works when executed from the Refresh button in the View) ViewModel中的RefreshData方法(从“视图”中的“刷新”按钮执行时有效)

    public void RefreshData()
    {
        InfoPanelVisible = Visibility.Hidden;
        InfoSummaryVisible = Visibility.Visible;
        Task.Run(() => LoadData());
        n = DateTime.Now;
        ProgressBarText = "Click a project to show progress";
        ProgressBarValue = 0;
        lastRefresh.Reset();
        lastRefresh.Start();
    }

LoadData method (and associated methods) called from RefreshData 从RefreshData调用的LoadData方法(和关联的方法)

    public async void LoadData()
    {
        IsLoading = Visibility.Visible;
        await GetWebApiInfo();
        MonitorData downloadInfo = main;
        try { AssignDataToControls(downloadInfo); }
        catch (Exception e) { Console.WriteLine("Error: " + e); }
        finally { IsLoading = Visibility.Hidden; }
    }

    public void AssignDataToControls(MonitorData mon)
    {
        MainPanel.Clear();
        MonitorText.Clear();
        mon.MainPanel.ToList().ForEach(x => MainPanel.Add(x));
        mon.MonitorText.ToList().ForEach(x => MonitorText.Add(x));
        Information = mon.Information;
        ProgressData = mon.progList;
    }

    public async Task GetWebApiInfo()
    {
        var url = "::::WEB API ADDRESS::::";
        string responseFromServer;
        using (HttpClient _client = new HttpClient())
        using (var dataStream = await _client.GetStreamAsync(url))
        using (var reader = new StreamReader(dataStream, Encoding.Unicode))
            responseFromServer = await reader.ReadToEndAsync();
        var deserializer = new JavaScriptSerializer();
        main = deserializer.Deserialize<MonitorData>(responseFromServer);
    } 

RefreshCommand from ViewModel Commands.cs file 来自ViewModel Commands.cs文件的RefreshCommand

internal class RefreshCommand : ICommand 
{
    public RefreshCommand(MMViewModel viewModel)
    {
        _viewModel = viewModel;
    }

    private MMViewModel _viewModel;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {
        return _viewModel.CanRefresh;
    }

    public void Execute(object parameter)
    {
        _viewModel.RefreshData();
    }
}

Solved this issue. 解决了这个问题。 The problem was that my ViewModel was being constructed three separate times, so it was unclear to the command which instance was being referenced. 问题是我的ViewModel被构造了三个不同的时间,因此不清楚命令所引用的是哪个实例。

To fix this, I removed references to the ViewModel in my XAML Window definition space. 为了解决这个问题,我在XAML窗口定义空间中删除了对ViewModel的引用。 There were 2 references I thought I needed for the ViewModel as a local namespace (ie x:local.VM="MM.MyViewModel"). 我认为我需要将ViewModel作为本地名称空间使用2个引用(即x:local.VM =“ MM.MyViewModel”)。 After removing those, the ViewModel is only being constructed once and all code is running as intended. 删除这些代码后,仅创建一次ViewModel,并且所有代码均按预期运行。 Thanks to @Will for his help getting to the bottom of this! 感谢@Will的帮助,帮助您深入浅出!

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

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