2013年10月9日水曜日

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

ModalPopupExtenderで検索して来られる方が多いようなので、
自分のために、あなたのために書いておきます。

ポップアップ画面にはグリッドが配置されていて、グリッドで選択したデータの値を
呼び出し元のラベルに表示します。
ついでにグリッドのデータは検索で絞り込みができるようにします。

呼び出し元画面には検索ワードを入れるテキストボックスがあり、
ポップアップ表示ボタンを押すと、ポップアップ画面に検索ワードを渡し、ポップアップ表示します。



文章で説明は面倒なのでコード読んでね。

ではまずポップアップ画面から作成です。
ポップアップ画面は使いまわせるようにユーザーコントロールで作成しました。

ModalPopupSample.aspxのデザイナです。
ModalPopupExtenderの設定に注目です。
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="PopUp.ascx.vb" Inherits="WebApplication1.PopUp" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>

<asp:Panel ID="pnlPopup" runat="server" BackColor="#C0C0FF">
    <asp:UpdatePanel ID="updPopup" runat="server" UpdateMode="Conditional">
        <ContentTemplate>

            <asp:Button ID="btnDummy" runat="server" Text="" Style="display: none" />

            <asp:ModalPopupExtender ID="modalPopupExtender" runat="server"
                TargetControlID="btnDummy"
                BackgroundCssClass="modalBackground"
                DropShadow="true"
                PopupControlID="pnlPopup"
                PopupDragHandleControlID="pnlTitle"
                CancelControlID="btnCancel" />

            <asp:Panel ID="pnlTitle" runat="server">
                ここにタイトル
            </asp:Panel>
            <div>
                ここに内容
                <br />
                検索条件:<asp:TextBox ID="txtSearch" runat="server"/><asp:Button ID="btnSearch" runat="server" Text="表示" />

                <asp:GridView ID="gvList" runat="server">
                    <Columns>
                        <asp:TemplateField HeaderText="選択">
                            <ItemTemplate>
                                <asp:LinkButton ID="lnkbtnSelect" runat="server" CommandName="select">選択</asp:LinkButton>
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="列1">
                            <ItemTemplate>
                                <asp:Label ID="lblCol1" runat="server" Text="Label"></asp:Label>
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="列2">
                            <ItemTemplate>
                                <asp:Label ID="lblCol2" runat="server" Text="Label"></asp:Label>
                            </ItemTemplate>
                        </asp:TemplateField>
                    </Columns>
                </asp:GridView>
                <asp:Button ID="btnCancel" runat="server" Text="閉じる" />
            </div>
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Panel>

ModalPopupSample.aspxのコードです。
Public Class PopUp
    Inherits System.Web.UI.UserControl

    ''' <summary>
    ''' ダイアログを閉じたイベントのイベント引数
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ClosedEventArgs
        Public Property Col1Value As String
        Public Property Col2Value As String
    End Class

    ''' <summary>
    ''' ダイアログを閉じた際のイベント
    ''' </summary>
    ''' <param name="arg"></param>
    ''' <remarks></remarks>
    Public Event DialogClosed(arg As ClosedEventArgs)


    ''' <summary>
    ''' ポップアップウインドウを表示
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Show(sArg As String)
        Me.txtSearch.Text = sArg 
        Me.gvList.Visible = True
        If Not String.IsNullOrEmpty(Me.txtSearch.Text) Then
            SetGridData()
        End If
        Me.updPopup.Update()
        Me.modalPopupExtender.Show()
    End Sub

    ''' <summary>
    ''' 表示ボタンClickイベント
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
        Me.gvList.Visible = True
        SetGridData()
        Me.updPopup.Update()
        Me.modalPopupExtender.Show()
    End Sub

    ''' <summary>
    ''' グリッドのRowDataBoundイベント
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub gvList_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvList.RowDataBound
        If e.Row.RowType <> DataControlRowType.DataRow Then
            Return
        End If

        Dim drv As DataRowView = DirectCast(e.Row.DataItem, DataRowView)
        '選択
        Dim args() As String = New String() {drv.Item("col1").ToString(), drv.Item("col2").ToString()}
        Dim lnkbtnSelect As LinkButton = DirectCast(e.Row.FindControl("lnkbtnSelect"), LinkButton)
        lnkbtnSelect.CommandArgument = String.Join(",", args)
        '列1
        Dim lblCol1 As Label = DirectCast(e.Row.FindControl("lblCol1"), Label)
        lblCol1.Text = drv.Item("col1").ToString()
        '列2
        Dim lblCol2 As Label = DirectCast(e.Row.FindControl("lblCol2"), Label)
        lblCol2.Text = drv.Item("col2").ToString()
    End Sub
    
    ''' <summary>
    ''' グリッドのRowCommandイベント
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub gvList_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles gvList.RowCommand
        Me.gvList.Visible = False
        Me.modalPopupExtender.Hide()
        Dim args() As String = e.CommandArgument.ToString.Split(","c)
        Dim eventArgs As New ClosedEventArgs
        eventArgs.Col1Value = args(0)
        eventArgs.Col2Value = args(1)
        RaiseEvent DialogClosed(eventArgs)
    End Sub

    ''' <summary>
    ''' グリッドデータ表示
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub SetGridData()
        'データ取得
        Dim sSearch As String = Me.txtSearch.Text
        Dim tbl As New DataTable
        tbl.Columns.Add(New DataColumn("col1", GetType(String)))
        tbl.Columns.Add(New DataColumn("col2", GetType(String)))
        For idx As Integer = 1 To 10
            tbl.Rows.Add(New Object() {idx.ToString, sSearch & idx.ToString})
        Next

        Me.gvList.DataSource = tbl
        Me.gvList.DataBind()
    End Sub


次に呼び出し画面の作成です。

Default.aspxのデザイナです。
ToolkitScriptManagerを配置し、先ほど作成したPopUpユーザーコントロールを配置します。
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="WebApplication1._Default" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<%@ Register Src="~/PopUp.ascx" TagPrefix="uc1" TagName="PopUp" %>


<!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">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server"></asp:ToolkitScriptManager>
        <div>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
                <ContentTemplate>
                    検索条件:<asp:TextBox ID="txtSearch" runat="server" /><asp:Button ID="btnShowPopup" runat="server" Text="ポップアップ表示" /><br />
                    列1:<asp:Label ID="lblCol1Value" runat="server"/><br />
                    列2:<asp:Label ID="lblCol2Value" runat="server"/><br />
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
        <uc1:PopUp runat="server" id="PopUp" />
    </form>
</body>
</html>
Default.aspxのコードです。
Public Class _Default
    Inherits System.Web.UI.Page

    Private Sub btnShowPopup_Click(sender As Object, e As EventArgs) Handles btnShowPopup.Click
        'ポップアップ画面の表示
        Me.PopUp.Show(Me.txtSearch.Text)
    End Sub

    Private Sub ModalPopupSample_DialogClosed(arg As PopUp.ClosedEventArgs) Handles PopUp.DialogClosed
        'ポップアップ画面を閉じたとき
        Me.lblCol1Value.Text = arg.Col1Value
        Me.lblCol2Value.Text = arg.Col2Value
        Me.UpdatePanel1.Update()
    End Sub

End Class

説明は以上!!

ASP.NET Global_asaxのApplication_Errorからカスタムエラーページが表示されない

1歳児のお世話をしているとブログを書く時間はないデス。
でも今日はハマったので未来の自分のためにメモです。


Global_asaxのApplication_Errorイベントで
Server.Transferでカスタムエラーページを表示しているのですが
.netのエラーページが表示されてしまい、カスタムエラーページが表示されません。
環境はVS2012,Fw3.5です。
まったく同じコードでもVS2008,Fw2.0ではちゃんと動きます。


こういうのわかりにくいから勘弁してほしい…。

ASP.NETのGlobal_asaxのコードです。
Application_Errorイベントでカスタムエラーページを表示します。
Imports System.Web.SessionState

Public Class Global_asax
    Inherits System.Web.HttpApplication

     Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
        ' エラーの発生時に呼び出されます
        'カスタムエラーページを表示します。
        Server.Transfer("~/CustomError.aspx")
    End Sub

End Class


カスタムエラーページではエラー内容を表示してます。

結論いうと、Loadイベントでエラーを出力した後、Context.ClearError() を呼んであげればちゃんと動きました。
CustomError.aspx
Public Class CustomError
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim ex As Exception
        ex = Server.GetLastError
        If TypeOf ex Is HttpUnhandledException AndAlso ex.InnerException IsNot Nothing Then
            ex = ex.InnerException
        End If

        If ex IsNot Nothing Then
            Me.Label1.Text = ex.GetType.ToString
            Me.Label2.Text = ex.Message
        End If

        Context.ClearError() '<--これが必要。
    End Sub

End Class


web.configです
<system.web>
     <customErrors mode="On"/>
</system.web>