经过很多年我再次学习C#。我在2.0天内做了C#编程。这种语言确实在进化,而且非常棒。话虽这么说,我正在制作W8 / WP8通用应用程序。基本上,当应用程序启动时,构造函数会运行一个方法。此方法检查连接,如果启用了连接,程序将向前流动。
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand(
"Try again", new UICommandInvokedHandler(this.UpdateInformationSection)));
// Show the message dialog
await msgdialog.ShowAsync();
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
因此,如果您注意到,如果连接失败,则会弹出一个消息对话框。弹出窗口中有一个“再试一次”按钮。当用户单击此按钮时,它具有与之关联的“回调函数”(对我来说是新的东西,我猜它就像一个事件处理程序?)。无论如何,我没有编写新方法,而是使回调方法与执行消息框的当前方法相同。所以基本上我所做的是添加了一个参数,所以我有UpdateInformationSection(IUICommand command)
。然后回调函数是相同的方法。
我害怕的是:每当他们点击“再试一次”按钮时,它会破坏它的旧实例吗?换句话说,当他们点击“再试一次”按钮时,该方法是否完成执行?否则我想象的是一个场景,一次又一次地调用该方法,并且每个方法都陷入困境(如果这有意义的话)。
此外,在我的构造函数中,当方法被FIRST调用时,我不得不将其更改为
//Update HUB Sections.
// send null as argument since its not coming from a "command button"
// the argument is required when the API connection cant be established
// and thus a modal dialog comes up with a "try again" command button.
UpdateInformationSection(null);
是否可以像“命令”参数一样发送“null”?什么是正确的程序。
答案 0 :(得分:0)
当然,这里没有真正的递归,因为你正在使用async
。但它 可能(实际上可能,但我没有经过双重检查)MessageDialog
没有完成ShowAsync()
方法调用,直到你自己的命令委托完成。这将导致MessageDialog
的多个实例仍然可以访问,直到您最终无法显示它,防止它们被垃圾收集(即最接近托管对象的实际内存泄漏)。
恕我直言,如果你通过排队再次执行方法而不是直接调用它来避免这种潜在的重入,那么该方法会更好地实现。这可能看起来像这样:
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand("Try again"));
// Show the message dialog
await msgdialog.ShowAsync();
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
return;
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
这样,每次显示MessageDialog
时,都会有机会在重新显示之前继续关闭。
以上假设"再试一次"真的是你提出的唯一选择。当然,如果您有其他选项,则可以使用UICommand对象来区分所选选项并执行相应的操作; "再试一次"会再次对RunAsync()
方法进行上述调用,而其他选项可以做任何事情。
所有这一切,我个人认为最好避免这种模式。据推测,用户做了最初启动此对话框的其他操作。至少,还应该有一个"取消"选项作为"再试一次"的替代方案。而恕我直言,实际上最好将此作为默认"关闭"的警报,以便用户只需将其带回到任何地方,以便在他们修复配置问题后,他们可以只是明确地再次尝试动作/操作。
我当然在这里对程序做出一些假设。由于缺乏具体的细节,我承认可能有一些令人信服的理由以你现在的方式做到这一点。但至少可以肯定这是最好的方法。将用户置于可能无限循环中似乎有点"关闭"对我来说。 :)
修改强>
详细说明这段代码:
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
RunAsync()
方法导致给定的委托在Dispatcher
的线程中执行,即程序的UI线程。这是该方法已经(可能)运行的地方,因为它是由某个UI对象调用的命令。这样做可以重新调用该方法,但是以不可重入的方式。即允许当前方法调用完成并在下一个方法调用开始之前返回。这消除了任何递归方面。
调用的委托本身 - () => { var ignoreTask = UpdateInformationSection(command); }
- 使用语句体lambda语法,只是再次调用命令方法的方法调用。
最后,RunAsync()
方法和命令方法都是async
方法,返回Task
个实例。在这种特殊情况下,我们不需要等待他们完成,所以没有await
,但如果我们不做某事编译器将返回值生成警告。对我来说,抑制警告的最简单,最干净的方法是继续将Task
引用复制到局部变量,这足以使编译器满意。 RunAsync()
方法被复制到名为_
的变量中,这是我通常用于实际上不需要使用的变量的变量,而命令方法的返回值是复制到名为ignoreTask
的变量,以这种方式命名,以明确变量的目的(忽略从命令方法返回的Task
)。