2010年9月8日水曜日

プロコン2010-1その3

久しぶりに更新。
今回は、共通画面構成を作ります。

で、先に完成画面から、
こんな感じで作ってみます。



実際はこんな感じで分割してみたいと。


上から順に、LoginStatus区画、UserTitle区画、TopicPath区画、Contents区画とします。
で、Contents区画は入れ子構造でLeftSideContents(左側)、PageContents(中央側)を持つものとします。
早速コードを見てみます。以下のコードが、~/Users.Masterの内容です。


<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Users.Master.cs" Inherits="Library.Users" %>

<!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>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div id="LoginStatus">
<asp:LoginView ID="LoginView1" runat="server">
<LoggedInTemplate>
<asp:LoginName ID="LoginName1" runat="server" />
でログイン中。
</LoggedInTemplate>
<AnonymousTemplate>
未ログインです。
</AnonymousTemplate>
</asp:LoginView>
<asp:LoginStatus ID="LoginStatus1" runat="server" />
</div>
<div id="UserTitle">
書籍貸し出し管理システム
</div>
<div id="TopicPath">
<asp:SiteMapPath ID="SiteMapPath1" runat="server">
</asp:SiteMapPath>
</div>
<div id="Contents">
<div id="LeftSideContents">
<asp:Menu ID="Menu1" runat="server">
<Items>
<asp:MenuItem NavigateUrl="~/User/SearchBook.aspx" Text="検索" Value="書籍の検索"></asp:MenuItem>
<asp:MenuItem NavigateUrl="~/User/RentalBook.aspx" Text="貸出" Value="書籍の貸し出しと返却">
</asp:MenuItem>
<asp:MenuItem Text="書籍" Value="書籍のメンテナンス">
<asp:MenuItem NavigateUrl="~/User/AddBook.aspx" Text="追加" Value="書籍の追加"></asp:MenuItem>
<asp:MenuItem NavigateUrl="~/User/ModifyBook.aspx" Text="変更" Value="書籍の変更"></asp:MenuItem>
</asp:MenuItem>
</Items>
</asp:Menu>
</div>
<div id="PageContents">
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</div>
</form>
</body>
</html>




スタイルシートの指定は、、各ページのページディレクティブに書いています。まずは、コンテンツページのデザインから。
例えば、~/Default.aspxはこんな感じ。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Library._Default"
MasterPageFile="~/Users.Master" StylesheetTheme="Standard" EnableTheming="True" %>

<asp:Content runat="server" ContentPlaceHolderID="ContentPlaceHolder1">
<p>
・左のメニューより利用したい機能を選択してください。</p>
<p>
・なお、このシステムを利用するためには権限が必要です。</p>
<p>
・ログインしても、権限のないページには移動できません。</p>
<p>
・ログインがOKでもユーザに権限が無い場合ログイン画面に戻されます。</p>
<p>
・書籍関係の操作には、Usersロール,ユーザ関係の操作にはAdminsロールが必要です。</p>
<p>
・ログイン中かの確認には、画面右上をご覧ください。</p>
<p>
 </p>
</asp:Content>


こんな感じで各ページが、右下のPageContentsしか触らないでよくなると、ページの統一感が出せそうだし、効率的に開発できそうな錯覚を感じることができそうですよね。

で、上のDefault.aspxの1行目Pageディテクティブで、StylesheetTheme="Standard"としていますね、
そこで、テーマStandardが選ばれているので、次にこのテーマのスタイルシートを見てみます。
~/App_Themes/Standard/Stylesheet1.cssにおいてあるファイル。

body
{
}
div#LoginStatus
{
height: 20px;
text-align: right;
position: relative;
}
div#UserTitle
{
height: 40px;
background-color: #00FF00;
border: solid medium Black;
font-size: x-large;
position: relative;
}
div#AdminTitle
{
height: 40px;
background-color: #FF0000;
border: solid medium Black;
font-size: x-large;
position: relative;
}
div#TopicPath
{
height: 20px;
position: relative;
border-bottom: solid thin Black;
}
div#Contents
{
}
div#LeftSideContents
{
width: 100px;
height:400px;
float: left;
position: relative;
}
div#PageContents
{
position: relative;
}


この3ファイルで、最初の画面が作られています。
こんな感じでマスターページを作ると、システム全体の構成の統一感を保てます。
、、、UserControlでもできるんじゃないかと突っ込まれることはあります。
もちろんUserControlでもマスターページと同様、入れ子構造で大きなパーツを
構成することができます。でも、UserControlは融通が利く分、ちょっと困難な場面があります。
例えば、、、なんだろう、ひょっとして無いのかな。(まじめに話すと、話が入り組んで来そうなので解説は止めときます。)

で、上のスタイルシートにある、AdminTitleとは何か?というと、以下の~/Admins.Masterというマスターページで使っています。

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Admins.Master.cs" Inherits="Library.Admins" %>

<!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>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div id="LoginStatus">
<asp:LoginView ID="LoginView1" runat="server">
<LoggedInTemplate>
<asp:LoginName ID="LoginName1" runat="server" />
でログイン中。
</LoggedInTemplate>
<AnonymousTemplate>
未ログインです。
</AnonymousTemplate>
</asp:LoginView>
<asp:LoginStatus ID="LoginStatus1" runat="server" />
</div>
<div id="AdminTitle">
書籍貸し出し管理システム(管理者がログイン)
</div>
<div id="TopicPath">
<asp:SiteMapPath ID="SiteMapPath1" runat="server">
</asp:SiteMapPath>
</div>
<div id="Contents">
<div id="LeftSideContents">
<asp:Menu ID="Menu1" runat="server">
<Items>
<asp:MenuItem NavigateUrl="~/User/SearchBook.aspx" Text="検索" Value="書籍の検索"></asp:MenuItem>
<asp:MenuItem NavigateUrl="~/User/RentalBook.aspx" Text="貸出" Value="書籍の貸し出しと返却">
</asp:MenuItem>
<asp:MenuItem Text="書籍" Value="書籍のメンテナンス">
<asp:MenuItem NavigateUrl="~/User/AddBook.aspx" Text="追加" Value="書籍の追加"></asp:MenuItem>
<asp:MenuItem NavigateUrl="~/User/ModifyBook.aspx" Text="変更" Value="書籍の変更"></asp:MenuItem>
</asp:MenuItem>
<asp:MenuItem Text="ユーザ" Value="ユーザのメンテナンス">
<asp:MenuItem NavigateUrl="~/Admin/AddUser.aspx" Text="追加" Value="ユーザの追加"></asp:MenuItem>
<asp:MenuItem NavigateUrl="~/Admin/ModifyUser.aspx" Text="変更" Value="ユーザの変更"></asp:MenuItem>
<asp:MenuItem NavigateUrl="~/Admin/DeleteUser.aspx" Text="削除" Value="ユーザの削除"></asp:MenuItem>
</asp:MenuItem>
</Items>
</asp:Menu>
</div>
<div id="PageContents">
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</div>
</form>
</body>
</html>



Users.masterとの違いは、タイトルの背景色、メニューアイテムの個数ぐらいです。
で、Admins.masterとUsers.masterはどんなページで切り替えるか?というと、ページ毎ではなく、ログインユーザ毎に切り替えようにします。
具体的には、Adminロールを持つユーザでログインしているときのみAdmins.masterを、それ以外はUsers.masterを使うようにします。
なので、プログラム構造に少し工夫を。。
Pageディテクティブに書いてあるマスターページの指定変更は、PagePreInitイベントの処理で切り替えることができます。ここで、ロールプロバイダを参照して切り替えることにします。
具体的には、以下のサブページクラスを作ります。(ソースコード配置は、~/App_Code/LibPage.csです。)

using System;

namespace Library
{
public class LibPage:System.Web.UI.Page
{
protected void Page_PreInit(object sender, EventArgs e)
{
if (User.IsInRole("Admins"))
{
Page.MasterPageFile = "~/Admins.Master";
}
}
}
}


で、全てのページのコードビハインド(~.aspx.cs)で、System.Web.UI.Pageから派生しているところを、すべてLibPageから派生させます。例えば、~/Default.aspx.csはこんな感じ

using System;

namespace Library
{
public partial class _Default : LibPage
{
protected void Page_Load(object sender, EventArgs e)
{

}
}
}




今回の記事の最後に、パンくずリストを構成するための~/Web.sitemapを付けておきます。

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~/Default.aspx" title="書籍貸出システム">
<siteMapNode url="~/Login.aspx" title="ログイン画面"/>
<siteMapNode url="" title="書籍管理">
<siteMapNode url="~/User/SearchBook.aspx" title="検索画面"/>
<siteMapNode url="~/User/AddBook.aspx" title="追加画面"/>
<siteMapNode url="~/User/ModifyBook.aspx" title="変更画面"/>
<siteMapNode url="~/User/DeleteBook.aspx" title="削除画面" />
</siteMapNode>
<siteMapNode url="" title="書籍貸し出し・返却">
<siteMapNode url="~/User/RentalBook.aspx" title="貸出画面"/>
<siteMapNode url="~/User/ReturnBook.aspx" title="返却画面"/>
</siteMapNode>
<siteMapNode url="" title="ユーザ管理">
<siteMapNode url="~/Admin/AddUser.aspx" title="追加画面"/>
<siteMapNode url="~/Admin/ModifyUser.aspx" title="変更画面"/>
<siteMapNode url="~/Admin/DeleteUser.aspx" title="削除画面"/>
</siteMapNode>
</siteMapNode>
</siteMap>

0 件のコメント: