2013年5月31日金曜日

ASP.NET モーダル画面の表示(ModalPopupExtender)

また久しぶりの投稿です。
PHPのお仕事が来るということでPHPの勉強をしていたのですが、来たのはASP.NETのお仕事でした。
ASP.NET久しぶりです。
最後にASP.NETで開発したのが2008年だから、5年ぶりだぁ(;´∀`)
もう記憶がほとんどないです。

ということで、今回の開発で詰まったところを、次回の開発のためにメモしておきます。
次のASP.NETのお仕事はいつかしら・・・

モーダル画面を表示

AjaxControlToolkitのModalPopupExtenderコントロールを使用してモーダル画面を表示する方法はコチラ。
@IT [ASP.NET AJAX]ModalPopupコントロールでモーダル・ウィンドウを生成するには?

サンプルとしてModalPopupExtenderを使用し、以下のようなメッセージダイアログを作成してみます。

まずはimageフォルダに質問、情報、警告、エラー時にメッセージに表示するアイコン画像を保存します。


メッセージダイアログ部分をユーザーコントロールで作成します。
「新しい項目の追加」 > 「Webユーザーコントロール」を選択します。
ファイル名は「Message.ascx」とします。

Message.ascxのソース
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Message.ascx.vb" Inherits="ModalPopupExtenderSample.Message" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>

<!-- ダミーボタン(非表示) -->
<asp:Button ID="btnDummy" runat="server" Text="Button" Style="display: none" />
<!-- ポップアップ部分 -->
<asp:Panel ID="pnlDialog" runat="server">
    <div class="dialog">
        <div class="title">
            <asp:Label ID="lblTitle" runat="server"></asp:Label>
        </div>
        <div class="content">
            <div class="icon">
                <asp:Image ID="Image1" runat="server" ImageUrl="" /></div>
            <div class="message">
                <asp:Label ID="lblMsg" runat="server"></asp:Label></div>
        </div>
        <br class="clearfloat" />
        <div class="button">
            <asp:Button ID="btnOk" runat="server" Text="OK" />
            <asp:Button ID="btnYes" runat="server" Text="Yes" />
            <asp:Button ID="btnNo" runat="server" Text="No" />
        </div>
    </div>
</asp:Panel>
<!-- ModalPopupExtender -->
<asp:ModalPopupExtender ID="modal" runat="server" TargetControlID="btnDummy" PopupControlID="pnlDialog"
    DropShadow="true" Drag="false" PopupDragHandleControlID="pnlDialog" BackgroundCssClass="modalBackground">
</asp:ModalPopupExtender>
Message.ascxのコード
Public Partial Class Message
    Inherits System.Web.UI.UserControl

    'ダイアログが閉じられたときに発生するイベントです。
    Public Event DialogClosed(ByVal dialogResult As DialogResultType, ByVal source As String, ByVal args() As Object)

    'ダイアログの表示タイプを示す列挙帯です。
    Public Enum StyleType
        Warning
        Information
        [Error]
        Question
    End Enum

    'ダイアログのどのボタンが押されたかを示す列挙帯です。
    Public Enum DialogResultType
        OK
        Yes
        No
    End Enum

    'ダイアログの表示スタイルです。
    Private _Style As StyleType
    'ダイアログのタイトルです。
    Private _sTitle As String
    'ダイアログのメッセージです。
    Private _sMessage As String

    'ダイアログの表示スタイルを取得・設定します。
    Public Property Style() As StyleType
        Get
            Return Me._Style
        End Get
        Set(ByVal value As StyleType)
            Me._Style = value
            'アイコン
            Dim url As String = String.Empty
            Select Case _Style
                Case StyleType.Warning
                    url = "~/image/warning.png"
                Case StyleType.Information
                    url = "~/image/info.png"
                Case StyleType.Error
                    url = "~/image/error.png"
                Case StyleType.Question
                    url = "~/image/question.png"
            End Select
            Me.Image1.ImageUrl = url
            'ボタン
            Select Case _Style
                Case StyleType.Question
                    Me.btnOk.Visible = False
                    Me.btnYes.Visible = True
                    Me.btnNo.Visible = True
                Case Else
                    Me.btnOk.Visible = True
                    Me.btnYes.Visible = False
                    Me.btnNo.Visible = False
            End Select
        End Set
    End Property
    'タイトルを取得・設定します。
    Public Property Title() As String
        Get
            Return Me._sTitle
        End Get
        Set(ByVal value As String)
            Me._sTitle = value
            Me.lblTitle.Text = value
        End Set
    End Property
    'メッセージを取得・設定します。
    Public Property Message() As String
        Get
            Return Me._sMessage
        End Get
        Set(ByVal value As String)
            Me._sMessage = value
            Me.lblMsg.Text = value
        End Set
    End Property
    'ダイアログを呼び出したオブジェクトを取得・設定します。
    Public Property Source() As String
        Get
            Return DirectCast(ViewState("Source"), String)
        End Get
        Set(ByVal value As String)
            ViewState("Source") = value
        End Set
    End Property
    'ダイアログを呼び出した際、任意の引数を取得・設定します。
    Public Property Args() As Object()
        Get
            Return DirectCast(ViewState("args"), Object())
        End Get
        Set(ByVal value As Object())
            ViewState("args") = value
        End Set
    End Property

    'ダイアログを表示します。
    Public Sub Show()
        Me.modal.Show()
    End Sub

    'Yesボタンが押された時の処理です。
    Private Sub btnYes_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) Handles btnYes.Command
        RaiseEvent DialogClosed(DialogResultType.Yes, Me.Source, Me.Args)
    End Sub
    'Noボタンが押された時の処理です。
    Private Sub btnNo_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) Handles btnNo.Command
        RaiseEvent DialogClosed(DialogResultType.No, Me.Source, Me.Args)
    End Sub
    'OKボタンが押された時の処理です。
    Private Sub btnOk_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) Handles btnOk.Command
        RaiseEvent DialogClosed(DialogResultType.OK, Me.Source, Me.Args)
    End Sub

End Class

次にダイアログ画面を呼び出す親画面です。

親画面を「Default.aspx」とします。
ToolkitScriptManager を「form」タグの先頭に配置します。
先ほど作成したMessageユーザーコントロールを配置します。

Default.aspxのソース
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="ModalPopupExtenderSample._Default" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<%@ Register Src="Message.ascx" TagName="Message" TagPrefix="uc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" />
    <div>
        <asp:Button ID="btnQuestion" runat="server" Text="Question" />
        <asp:Button ID="btnWarning" runat="server" Text="Warning" />
        <asp:Button ID="btnInformation" runat="server" Text="Information" />
        <asp:Button ID="btnError" runat="server" Text="Error" />
        <br />
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        
        <uc1:Message ID="Message1" runat="server" />
    </div>
    </form>
</body>
</html>
Default.aspxのコード
Partial Public Class _Default
    Inherits System.Web.UI.Page

    Private Sub btnQuestion_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) _
    Handles btnQuestion.Command
        Me.Message1.Style = Message.StyleType.Question
        Me.Message1.Title = "タイトル"
        Me.Message1.Message = "質問メッセージ。よろしいですか?"
        Me.Message1.Source = Me.btnQuestion.ClientID
        Me.Message1.Args = New Object() {"args1", "args2"}
        Me.Message1.Show()
    End Sub
    Private Sub btnWarning_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) _
    Handles btnWarning.Command
        Me.Message1.Style = Message.StyleType.Warning
        Me.Message1.Title = "タイトル"
        Me.Message1.Message = "警告メッセージ"
        Me.Message1.Source = Me.btnWarning.ClientID
        Me.Message1.Args = New Object() {"args3", "args4"}
        Me.Message1.Show()
    End Sub
    Private Sub btnInformation_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) _
    Handles btnInformation.Command
        Me.Message1.Style = Message.StyleType.Information
        Me.Message1.Title = "タイトル"
        Me.Message1.Message = "情報メッセージ"
        Me.Message1.Source = Me.btnInformation.ClientID
        Me.Message1.Args = New Object() {"args5", "args6"}
        Me.Message1.Show()
    End Sub
    Private Sub btnError_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) _
    Handles btnError.Command
        Me.Message1.Style = Message.StyleType.Error
        Me.Message1.Title = "タイトル"
        Me.Message1.Message = "エラーメッセージ"
        Me.Message1.Source = Me.btnError.ClientID
        Me.Message1.Args = New Object() {"args7", "args8"}
        Me.Message1.Show()
    End Sub

    Private Sub Message1_DialogClosed(ByVal dialogResult As Message.DialogResultType, ByVal source As String, ByVal args() As Object) _
    Handles Message1.DialogClosed
        Select Case source
            Case Me.btnQuestion.ClientID
                If dialogResult <> Message.DialogResultType.Yes Then
                    Return
                End If
                Me.Label1.Text = args(0).ToString

            Case Me.btnWarning.ClientID
                If dialogResult <> Message.DialogResultType.OK Then
                    Return
                End If
                Me.Label1.Text = args(0).ToString

            Case Me.btnInformation.ClientID
                If dialogResult <> Message.DialogResultType.OK Then
                    Return
                End If
                Me.Label1.Text = args(0).ToString

            Case Me.btnError.ClientID
                If dialogResult <> Message.DialogResultType.OK Then
                    Return
                End If
                Me.Label1.Text = args(0).ToString

        End Select
    End Sub
End Class
次にスタイルシートです。

「App_Themes」フォルダに「追加」>「ASP.NETフォルダの追加」>「Theme」を選択し、テーマ「theme1」を追加します。
「Theme1」フォルダに「追加」>「新しい項目」より「スタイルシート」を追加します。
ファイル名は「StyleSheet1.css」としました。

Default.aspxにテーマを設定するためweb.configを編集します。
<pages>ノードを探し、以下のように「theme="theme1"」を追加します。
<pages theme="theme1">
「StyleSheet1.css」の中身です。
.dialog { 
    background-color: #F0FFFF;
    width: 400px;
    min-width: 400px;
}
.dialog .title{ 
    background-color: #B0C4DE;
    padding: 5px 10px;
}
.dialog .content 
{
    width: 380px;
    padding: 10px;
    margin-bottom: 10px;
}
.dialog .icon
{
    float: left;
    width: 48px;
    margin-right: 12px;
}
.dialog .message
{
    float: left;
    width: 320px;
 word-break: break-all; /* 表示範囲に合わせて改行 */
    word-wrap: break-word; /* 必要に応じて単語の途中で改行する */
}    
.dialog .button
{
    padding: 10px 0;
    text-align: center;
}
.modalBackground
{
    background-color:black;
    filter:alpha(opacity=75); /* IE:透明度 透明にしちゃうと親画面が操作できてしまうので注意 */
    opacity:0.75;            /* Opera・Safari:透明度 */
    zoom:1;                  /* ModalPopupExtenderでポップアップ表示した際、親画面の背景スタイルがCSSで定義しても生きない(IEのみ)。有効にを適用させるために必要。*/
}

キモになるのは「.modalBackground」です。 「.modalBackground」はユーザーコントロール「Message.ascx」のソースで、ModalPopupExtenderのBackgroundCssClassプロパティに設定しています。
<!-- ModalPopupExtender -->
<asp:ModalPopupExtender ID="modal" runat="server" TargetControlID="btnDummy" PopupControlID="pnlDialog"
    DropShadow="true" Drag="false" PopupDragHandleControlID="pnlDialog" BackgroundCssClass="modalBackground">
</asp:ModalPopupExtender>
メッセージダイアログがポップアップ表示した際、親画面のスタイルを定義します。
まず半透明にしないと、メッセージダイアログを表示した際に親画面が操作できてしまいます。
次にスタイルシートでmodalBackgroundを定義すると、親画面が半透明になりません。
半透明にするためには「zoom:1」とするとよいそうです。
スタイルシートではなくMessage.ascx自体にmodalBackgroundのスタイルを定義するときは「zoom:1」は必要ありません。

今回ハマったのはスタイルシート「.modalBackground」の定義でした(ノД`)・゜・。


追記
ASP.NET ModalPopupExtenderでDataGridをポップアップ表示し選択した値を元の画面に設定する

1 件のコメント:

福永美佳 さんのコメント...

はじめまして。
美佳と申します。
.NETを勉強し始めてまだ日が浅いのでこの記事を活用させていただきました。

ボタンクリックでポップアップ表示させるプロセスは理解できたのですが、TextBox1_TextChangedでポップアップ表示させることができません。
ご教授願えませんでしょうか?
よろしくお願いします。