【发布时间】:2016-12-02 17:44:54
【问题描述】:
在使用 NotifyIcon 时,我似乎无法从我的 XAML 代码中成功运行 ViewModel 中的方法。该方法正确执行,在使用断点的调试模式下进行测试,但视图中没有任何反应。
有问题的方法是 RefreshData,它可以从视图中的按钮调用(按预期工作),或者右键单击 NotifyIcon 并选择 Refresh Data(什么都不做)。我将在下面发布相关代码。任何帮助将不胜感激!
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);
}
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();
}
从 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);
}
来自 ViewModel Commands.cs 文件的刷新命令
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();
}
}
【问题讨论】:
-
什么都没有出现在我身上。您声称“该方法执行正确”,但不清楚您在谈论什么方法。例如,如果您要在每个方法的开头放置断点,然后单击通知图标,那么您实际上设法将调用堆栈向下移动了多远?您可以在断点处添加一个 Action,这样它就可以打印出刚刚在调试控制台中执行的方法的名称,这很方便。
-
接下来,我将检查视图模型是您认为的那样的假设。在 LoadData 方法中放置一个断点。从任务栏触发它,当它被点击时,将一个对象 ID 分配给
this(如果您不知道对象 ID 是如何工作的,请搜索该术语)。接下来,从窗口触发它。当断点被命中时,检查this看它是否有一个对象id。如果没有,您的数据上下文正在以某种方式更改。 -
对我来说似乎是 CompositeCommand 的工作。这是一个“shell”命令,允许各种 VM 订阅它以处理 CanExecute / Execute。
-
@Will 在 LoadData 的左大括号上有一个断点,我得到这个:从 MM.ViewModel.MMViewModel.RefreshData.AnonymousMethod__68_0 调用的 MM.ViewModel.MMViewModel.LoadData()。我将此设置为操作:从 $CALLER 调用的 $FUNCTION。应用程序中的刷新按钮有效,通过右键单击 Windows 系统托盘中的 NotifyIcon 运行刷新数据不起作用,但它返回的输出与我刚刚在上面列出的相同。
-
我会一直追踪到调用堆栈以确保(此时没有假设),然后去做对象 id 的事情,