C#异步方法不运行模态

时间:2015-12-08 11:37:45

标签: c# wpf async-await mahapps.metro

我的源代码中存在一个问题,即异步方法不是模态的。 我正在使用Mahapps Metro Framework,并且我有一个带有两个异步方法的Logger-Class:

public class Logger : ILogger {

    public void outputMessage(string message) {
        Console.WriteLine(message);
    }

    public void outputUserMessage(string message) {
        MessageBox.Show(message);
    }

    public async void outputMetroUserMessage(object window, String title, String message) {
        MetroWindow mWindow = (MetroWindow)window;
        await mWindow.ShowMessageAsync(title, message);
    }

    public async void outputMetroUserMessageWithHidingMDI(object window, string title, string message) {
        UIGlobals.MainPageMdiChild.Visibility = Visibility.Hidden;
        MetroWindow mWindow = (MetroWindow)window;
        await mWindow.ShowMessageAsync(title, message);
        UIGlobals.MainPageMdiChild.Visibility = Visibility.Visible;
    }
}

还有一些其他类的方法可以调用Logger方法。示例:

public partial class Login : MetroWindow {
    public Login() {
        InitializeComponent();
    }

    private void button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
        DoLogin();            
    }

    private void DoLogin() {
        String email = txtEMail.Text;
        String password = txtPassword.Password;

        if (String.IsNullOrWhiteSpace(email)) {
            Globals.Logger.outputMetroUserMessage(this, UserErrorMessageController.GetTitleByID(103), UserErrorMessageController.GetMessageByID(103));
        } else if (String.IsNullOrWhiteSpace(password)) {
            Globals.Logger.outputMetroUserMessage(this, UserErrorMessageController.GetTitleByID(104), UserErrorMessageController.GetMessageByID(104));
        } else {

            .
            .
            .
        }
    }
 }

ProfileCreator:

public partial class ProfileCreator : MetroWindow {

    public ProfileCreator(Network tempNetwork, UserProfile tempProfile) {
        InitializeComponent();
        .
        .
        .
    }



    private void btnSave_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
        // TODO: Set cancelling when someting is missing

        Save();
    }

    private void Save() {
        getUserProfileValuesFromWindow();

        Globals.TheSerializer.Serialize(tempProfile, Globals.PathToTemporaryFiles + "MyProfile.xml");

        tempNetwork.NetworkParticipants.Add(tempProfile.ParticipantID);

        Globals.TheSerializer.Serialize(tempNetwork, Globals.PathToTemporaryFiles + "MyNetwork.xml");

        Globals.Logger.outputMetroUserMessage(this, "Erfolg", "Ihr Testsystem wurde erfolgreich angelegt.\nDrücken Sie erneut auf \"Testen\" und loggen Sie sich ein.");
        Globals.Logger.outputMetroUserMessage(this, UserErrorMessageController.GetTitleByID(104), UserErrorMessageController.GetMessageByID(104));
    }

当我在Login-Class中调用Loggers方法时,方法按预期运行模态,但如果我从ProfileCreator调用它们,它们似乎不是模态的。我试图解决它,但我看不出类和参数的任何差异。也许你会看到我没有做过的事情。

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

问题是您没有使用Task。最佳做法是从WPF中的用户单击事件未调用的所有Task方法返回async。您的代码应如下所示:

public class Logger : ILogger
{
    public void outputMessage(string message)
    {
        Console.WriteLine(message);
    }

    public void outputUserMessage(string message)
    {
        MessageBox.Show(message);
    }

    public Task<MessageDialogResult> outputMetroUserMessage(object window, String title, String message)
    {
        MetroWindow mWindow = (MetroWindow)window;
        return mWindow.ShowMessageAsync(title, message);
    }

    public async Task outputMetroUserMessageWithHidingMDI(object window, string title, string message)
    {
        UIGlobals.MainPageMdiChild.Visibility = Visibility.Hidden;
        MetroWindow mWindow = (MetroWindow)window;
        await mWindow.ShowMessageAsync(title, message);
        UIGlobals.MainPageMdiChild.Visibility = Visibility.Visible;
    }
}

并按原样使用它:

public partial class Login : MetroWindow
{
    public Login()
    {
        InitializeComponent();
    }

    private async void button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        await DoLogin();
    }

    private async Task DoLogin()
    {
        String email = txtEMail.Text;
        String password = txtPassword.Password;

        if (String.IsNullOrWhiteSpace(email))
        {
            await Globals.Logger.outputMetroUserMessage(this, UserErrorMessageController.GetTitleByID(103), UserErrorMessageController.GetMessageByID(103));
        }
        else if (String.IsNullOrWhiteSpace(password))
        {
            await Globals.Logger.outputMetroUserMessage(this, UserErrorMessageController.GetTitleByID(104), UserErrorMessageController.GetMessageByID(104));
        }
        else
        {
            // ...
        }
    }
}

请注意,我只在UI上的事件处理程序中使用async void,这应该是您使用该模式的唯一位置。请仔细阅读this以获取解释。

这是最后一篇,除非你是来自UI交互的事件处理程序的方法,否则不要使用async void。

public partial class ProfileCreator : MetroWindow
{
    public ProfileCreator(Network tempNetwork, UserProfile tempProfile)
    {
        InitializeComponent();
        // ...
    }

    async void btnSave_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        // TODO: Set cancelling when someting is missing
        await Save();
    }

    async Task Save()
    {
        getUserProfileValuesFromWindow();

        Globals.TheSerializer.Serialize(tempProfile, Globals.PathToTemporaryFiles + "MyProfile.xml");

        tempNetwork.NetworkParticipants.Add(tempProfile.ParticipantID);

        Globals.TheSerializer.Serialize(tempNetwork, Globals.PathToTemporaryFiles + "MyNetwork.xml");

        await Globals.Logger.outputMetroUserMessage(this, "Erfolg", "Ihr Testsystem wurde erfolgreich angelegt.\nDrücken Sie erneut auf \"Testen\" und loggen Sie sich ein.");
        await Globals.Logger.outputMetroUserMessage(this, UserErrorMessageController.GetTitleByID(104), UserErrorMessageController.GetMessageByID(104));
    }
}

答案 1 :(得分:1)

那是因为你打电话给你的异步方法&#34; outputMetroUserMessage&#34;两次,没有等待第一个的结果。你可以像这样重新定义你的方法:

public Task<MessageDialogResult> OutputMetroUserMessage(object window, string title, string message)
{
   MetroWindow mWindow = (MetroWindow)window;
   return mWindow.ShowMessageAsync(title, message);
}

然后等待消息输出:

private async void button1_Click(object sender, RoutedEventArgs e)
        {
            await this.OutputMetroUserMessage(this, "Title", "Message1");
            await this.OutputMetroUserMessage(this, "Title", "Message2");
        }

第二次通话将在用户确认消息后执行。

希望有所帮助。

相关问题