воскресенье, 3 марта 2013 г.

Упрощения жизни в примере показа всплывающих сообщений


В прошлой статье, был пример разработки метода, позволяющего показать информационное окно с картинкой. На мой взгляд, единственным недостатком приведенного метода, является сложность его вызова. Действительно, чтобы  показать достаточно простое окно, нам пришлось создавать экземпляры класса PopubButton, задавать имена и т.д. давайте сегодня посмотрим пример паттерна Фасад, который позволит упростить жизнь тем, кто решит воспользоваться этим классом.

Паттерн фасад – применяется в тех случаях, когда у нас есть некий сложный метод, класс, система или совокупность подсистем, а мы добавляем новый фасад, который позволяется пользоваться этими сложными сущностями проще или, что также бывает актуально, чуть по другому.
Ну и давайте посмотрим оба эти варианта. Первый пример будет упрощать вызов в специфических случаях, второй пример позволит вызывать наш метод показа всплывающего окна и дожидаться выбора пользователя в том же методе.
Итак, для начала, сделаем версию метода, которая позволит показать сообщение с единственной кнопкой:

public static void Show(string p_message, BitmapImage p_image)
{
    ShowPopupMessage.Show(
        p_message,
        p_image,
        new PopupButton("Закрыть", null)
        );
}
Кода мы написали немного, но его наличие позволит при показ простых сообщений писать значительно короче:
ShowPopupMessage.Show(
                "Привет!",
                new BitmapImage(new Uri("http://lh5.googleusercontent.com/-xqEMlkTQlNU/AAAAAAAAAAI/AAAAAAAAA38/-AC-DOM0IIA/s512-c/photo.jpg"))               
                );
С другой стороны, добавив этот метод, мы можем упростить, например, локализацию. Теперь, вместо того, чтобы бегать по всей программе и заменять Закрыть на Close, мы можем это сделать в одном месте.
Для второго примера давайте сделаем чуть более универсальный метод, который позволит нам достаточно просто показывать окно с несколькими кнопками. Для этого, добавим в программу два перечисления.
public enum PopupButtons
{
    YesNo,
    YesNoCancel,
    OkCancel
}
 
public enum PopupResult
{
    Yes,
    No,
    Ok,
    Cancel
}
Ну и метод, который будет показывать Popup сообщения с необходимым набором кнопок. Кстати, второе перечисление нам необходимо, чтобы сообщать в основное окно, с каким результатом мы закрыли сообщение.
Т.к. в этом случае, мы показываем сообщение и хотим дождаться результата с которым Popup закроется, давайте сделаем наш метод с претензией на асинхронность. Т.е. метод будет возвращать задачу от PopupResult. Обратите внимание, что на самом деле в моем методе нет, так называемых, «длительных операций», в качестве такой операции у меня время от показа сообщения, до того момента, когда пользователь нажмет одну из кнопок.
public static Task<PopupResult> ShowAsync(string p_message, BitmapImage p_image, PopupButtons p_buttons)
{
    PopupResult result = PopupResult.Cancel;
    Task<PopupResult> task = new Task<PopupResult>((Func<PopupResult>)(() => result));
    PopupButton[] buttons = null;
    switch (p_buttons)
    {
        case PopupButtons.YesNo:
            buttons = new PopupButton[]
            {
                    new PopupButton("Да", () => { result = PopupResult.Yes; task.Start(); }),
                    new PopupButton("Нет", () => { result = PopupResult.No; task.Start(); }),
            };
            break;
        case PopupButtons.YesNoCancel:
            buttons = new PopupButton[]
            {
                    new PopupButton("Да", () => { result = PopupResult.Yes; task.Start(); }),
                    new PopupButton("Нет", () => { result = PopupResult.No; task.Start(); }),
                    new PopupButton("Отмена", () => { task.Start(); }),
            };
            break;
        case PopupButtons.OkCancel:
            buttons = new PopupButton[]
            {
                    new PopupButton("Ок", () => { result = PopupResult.Ok; task.Start(); }),
                    new PopupButton("Отмена", () => { task.Start(); }),
            };
            break;
    }
    Show(p_message, p_image, buttons);
    return task;
}
Ну и как теперь этим можно воспользоваться:
private async void Button_Click_1(object sender, RoutedEventArgs e)
{           
    PopupResult result = await ShowPopupMessage.ShowAsync(
        "Привет!",
        new BitmapImage(new Uri("http://lh5.googleusercontent.com/-xqEMlkTQlNU/AAAAAAAAAAI/AAAAAAAAA38/-AC-DOM0IIA/s512-c/photo.jpg")),
        PopupButtons.YesNoCancel);
    switch (result)
    {
        case PopupResult.Yes:
            tbResult.Text = "Нажали да";
            break;
        case PopupResult.No:
            tbResult.Text = "Нажали Нет";
            break;
        case PopupResult.Cancel:
            tbResult.Text = "Нажали Отмена";
            break;
    }
}
Как видно, теперь у нас появилась возможность показать сообщение, и дождаться результата который выберет пользователь. Согласитесь удобно.
Ну и картинка, для последнего примера:
 

3 комментария:

  1. Класс, действительно очень удобно.
    Можете мне посоветовать хорошую книгу для изучения паттернов?

    ОтветитьУдалить