<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
    CodeFile="ProjectEdit.aspx.cs" Inherits="PTWeb.ProjectEdit" Title="项目信息" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
    <div>
        <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
            <!-- 视图1 -->
            <asp:View ID="MainView" runat="server">
                <!-- 提供项目编辑显示 
                AutoGenerateRows="False" 的好处在于可以优化访问,代码可以控制她的刷新,这样只在有更新的时候调用DataBind()方法刷新
                -->
                <asp:DetailsView ID="DetailsView1" runat="server" Height="50px" Width="536px" AutoGenerateRows="False"
                    DataSourceID="ProjectDataSource" DataKeyNames="Id" OnItemDeleted="DetailsView1_ItemDeleted"
                    OnItemInserted="DetailsView1_ItemInserted" OnItemUpdated="DetailsView1_ItemUpdated"
                    OnItemCreated="DetailsView1_ItemCreated">
                    <Fields>
                        <asp:BoundField DataField="Id" HeaderText="编号" ReadOnly="True" SortExpression="Id"
                            InsertVisible="False">
                            <ItemStyle Width="90%" />
                        </asp:BoundField>
                        <asp:BoundField DataField="Name" HeaderText="名字" SortExpression="Name">
                            <ControlStyle Width="90%" />
                        </asp:BoundField>
                        <asp:BoundField DataField="Started" HeaderText="开始时间" SortExpression="Started">
                            <ControlStyle Width="90%" />
                        </asp:BoundField>
                        <asp:BoundField DataField="Ended" HeaderText="结束时间" SortExpression="Ended">
                            <ControlStyle Width="90%" />
                        </asp:BoundField>
                        <%-- 描述是一个模板列,她提供了
                       编辑,添加,显示三种状态的显示模板
                       
                       --%>
                        <asp:TemplateField HeaderText="描述" SortExpression="Description">
                            <EditItemTemplate>
                                <asp:TextBox ID="TextBox1" TextMode="MultiLine" Width="90%" runat="server" Text='<%# Bind("Description") %>'></asp:TextBox>
                            </EditItemTemplate>
                            <InsertItemTemplate>
                                <asp:TextBox ID="TextBox1" TextMode="MultiLine" Width="90%" runat="server" Text='<%# Bind("Description") %>'></asp:TextBox>
                            </InsertItemTemplate>
                            <ItemTemplate>
                                <asp:TextBox ID="TextBox1" TextMode="MultiLine" ReadOnly="true" Width="90%" runat="server"
                                    Text='<%# Bind("Description") %>'></asp:TextBox>
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowInsertButton="True" />
                    </Fields>
                </asp:DetailsView>
                &nbsp;&nbsp;&nbsp;<br />
                <!-- 提供相关项目的资源分派列表,也就是子表的显示  -->
                <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AutoGenerateColumns="False"
                    DataSourceID="ResourcesDataSource" Width="432px" DataKeyNames="ResourceId">
                    <Columns>
                        <asp:BoundField DataField="ResourceId" HeaderText="ResourceId" ReadOnly="True" SortExpression="ResourceId"
                            Visible="False" />
                        <%-- 显示的文本是
                            DataTextField="FullName" 全名
                        --%>
                        <asp:HyperLinkField DataNavigateUrlFields="ResourceId" DataNavigateUrlFormatString="ResourceEdit.aspx?id={0}"
                            DataTextField="FullName" HeaderText="名字" />
                        <asp:BoundField DataField="Assigned" HeaderText="分配" ReadOnly="True" SortExpression="Assigned" />
                        <%-- 提供了职务的模板,她是一个列表,
                            在编辑模式下 将其激活
                            显示模式下 将Enabled="False" 设置为假
                            DataTextField="Value" DataValueField="Key" 分别代表对象的数据源的属性
                            由于数据源是RoleList(名值对列表)
                            SelectedValue='<%# Bind("Role") %>'> 很关键,首先你要知道<%# Bind("Role") %>是什么,这个是GridView1的资源
                            这样这个属性是用于设置DDL(DropDownList)当前显示的项目是谁
                         --%>
                        <asp:TemplateField HeaderText="职务" SortExpression="Role">
                            <EditItemTemplate>
                                <asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="RoleListDataSource"
                                    DataTextField="Value" DataValueField="Key" SelectedValue='<%# Bind("Role") %>'>
                                </asp:DropDownList>
                            </EditItemTemplate>
                            <ItemTemplate>
                                <asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="RoleListDataSource"
                                    DataTextField="Value" DataValueField="Key" Enabled="False" SelectedValue='<%# Bind("Role") %>'>
                                </asp:DropDownList>
                            </ItemTemplate>
                        </asp:TemplateField>
                        <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
                    </Columns>
                </asp:GridView>
                <asp:LinkButton ID="AddResourceButton" runat="server" OnClick="AddResourceButton_Click">添加资源</asp:LinkButton><br />
                <br />
                &nbsp;
            </asp:View>
            <!-- 视图2 -->
            <asp:View ID="AssignView" runat="server">
                <strong>选资源:</strong><br />
                <!-- OnSelectedIndexChanged在点选一个项目之后被激发 -->
                <asp:GridView ID="GridView2" runat="server" AllowPaging="True" AutoGenerateColumns="False"
                    DataKeyNames="Id" DataSourceID="ResourceListDataSource" OnSelectedIndexChanged="GridView2_SelectedIndexChanged">
                    <Columns>
                        <asp:BoundField DataField="Name" HeaderText="资源" ReadOnly="True" SortExpression="Name" />
                        <asp:CommandField ShowSelectButton="True" />
                    </Columns>
                </asp:GridView>
                <asp:LinkButton ID="CancelAssignButton" runat="server" OnClick="CancelAssignButton_Click">取消</asp:LinkButton><br />
                <%--只读资源列表做数据源--%>
                <csla:CslaDataSource ID="ResourceListDataSource" runat="server" TypeName="ProjectTracker.Library.ResourceList, ProjectTracker.Library"
                    OnSelectObject="ResourceListDataSource_SelectObject" TypeSupportsPaging="False"
                    TypeSupportsSorting="False">
                </csla:CslaDataSource>
            </asp:View>
        </asp:MultiView>
        
        <asp:Label ID="ErrorLabel" runat="server" ForeColor="Red"></asp:Label><br />
       
         <%-- 数据源集中区  项目基类资源--%>
        &nbsp;<csla:CslaDataSource ID="ProjectDataSource" runat="server" TypeName="ProjectTracker.Library.Project, ProjectTracker.Library"
            OnDeleteObject="ProjectDataSource_DeleteObject" OnInsertObject="ProjectDataSource_InsertObject"
            OnSelectObject="ProjectDataSource_SelectObject" OnUpdateObject="ProjectDataSource_UpdateObject"
            TypeSupportsPaging="False" TypeSupportsSorting="False">
        </csla:CslaDataSource>
        
        <%-- 用的项目分配类,维护分配关系 --%>
        <csla:CslaDataSource ID="ResourcesDataSource" runat="server" TypeName="ProjectTracker.Library.ProjectResources, ProjectTracker.Library"
            OnDeleteObject="ResourcesDataSource_DeleteObject" OnSelectObject="ResourcesDataSource_SelectObject"
            OnUpdateObject="ResourcesDataSource_UpdateObject" TypeSupportsPaging="False"
            TypeSupportsSorting="False">
        </csla:CslaDataSource>
        
        <%-- 名值对类表 --%>
        <csla:CslaDataSource ID="RoleListDataSource" runat="server" TypeName="ProjectTracker.Library.RoleList, ProjectTracker.Library"
            OnSelectObject="RoleListDataSource_SelectObject" TypeSupportsPaging="False" TypeSupportsSorting="False">
        </csla:CslaDataSource>
        <br />
    </div>
    <br />
    &nbsp;
</asp:Content>

 

//======================================================================
//     
//        Guid1:               91a22c9c-c56a-4986-8ea5-d3db474ed789
//        CLR版本:             2.0.50727.3053
//        新建项输入的名称:    ProjectEdit
//        机器名称:            SOFTWARE-FRT-08
//        命名空间名称:        PTWeb
//        文件名:              ProjectEdit
//        当前系统时间:        2008-10-2 19:07:41
//        用户所在的域:        TECHSTAR
//        当前登录用户名:      frt
//        创建年份:            2008
//
//        Created by Terry.Feng.C (冯瑞涛) at 2008-10-2 19:07:41
//        
//
//======================================================================

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using ProjectTracker.Library;

namespace PTWeb
{
    public partial class ProjectEdit : System.Web.UI.Page
    {
        #region 私有成员
        private enum Views
        {
            MainView = 0,
            AssignView = 1
        }

        private void ApplyAuthorizationRules()
        {
            Project obj = GetProject();
            // 项目
            if (Project.CanEditObject())
            {
                if (obj.IsNew)
                    this.DetailsView1.DefaultMode = DetailsViewMode.Insert;
                else
                    this.DetailsView1.DefaultMode = DetailsViewMode.Edit;
                
                //新的是不显示的,因为此时这个项目还没有被实际存在(数据库中没有)
                
                //***其实在这里我有一些自己的看法
                //如果我们能够不在保存父对象的情况下,可以为其添加和建立子对象,将结果缓存起来,最后我们在父对象上点击保存,结果是把所有的父子,全都保存
                //CSLA的演示程序,在这里她并不是这样的,但是她是支持的,如果你没有建立一个父对象她是不会让你为其添加资源的,她没有这么实现,
                //你可以看一下GridView2_SelectedIndexChanged这个事件,他在这里进行了保存SaveProject,如果我们不调用它,是可以的,成功了!
                //
                // 注意! 理解Session和Obj是出于同一个引用是这次的关键!在98行
                //
                //在这里我分析了她当前能否实现这个需求,
                //1。他们的父子关系是多对多的关系,所以他们之间的分配是建立在一个中间表中的,这样中间表是需要父子两个表的主键为主键的


                //this.AddResourceButton.Visible = !obj.IsNew;
            }
            else
            {
                this.DetailsView1.DefaultMode = DetailsViewMode.ReadOnly;
                this.AddResourceButton.Visible = false;
            }

            //这两个控件都是视图1中的
            //由于Detailview是横向的,所以她是Rows.Count-1是最下面的控制行
            this.DetailsView1.Rows[this.DetailsView1.Rows.Count - 1].Visible = Project.CanEditObject();

            // 资源
            // 最后一列根据权限同步显示
            this.GridView1.Columns[this.GridView1.Columns.Count - 1].Visible = Project.CanEditObject();
        }

        /// <summary>
        /// 获得,并缓存一个项目对象
        /// </summary>
        /// <returns></returns>
        private Project GetProject()
        {
            //从缓存中取出项目对象
            //这里Session,将内容付给Object,实际上是将一个引用传递,那么这代表这,如果Object这个对象,也就是GetProject返回的这个对象改变,同时也会影响
            //Session["currentObject"] 的值,这是一个突破的理解,你在导出Session的活动,实际上就是在用另一种形式在使用Session的内容
            object businessObject = Session["currentObject"]; //Session
            
            //如果不存在,进入
            if (businessObject == null || !(businessObject is Project))
            {
                try
                {
                    string idString = Request.QueryString["id"];
                    //不是空的,代表是编辑或者是显示方法进来的
                    if (!string.IsNullOrEmpty(idString))
                    {
                        //根据参数建立一个Guid
                        Guid id = new Guid(idString);
                        //获得这个项目
                        businessObject = Project.GetProject(id);
                    }
                    else     //是新建进来的
                        businessObject = Project.NewProject();


                    //最后都要把这个对象付给缓存Session
                    Session["currentObject"] = businessObject; //====Session
                }
                catch (System.Security.SecurityException)
                {
                    Response.Redirect("ProjectList.aspx");
                }
            }
            //将当前对象返回
            return (Project)businessObject; //在此加断点,用监视器监控Session["currentObject"]的变化
        }

        /// <summary>
        /// 这个方法用于保存一个工程,并将结果缓存,实际上,这个工程只是扩展了异常捕获的范围,(556)
        /// </summary>
        /// <param name="project"></param>
        /// <returns></returns>
        private int SaveProject(Project project)
        {
            //要返回的行影响标记
            int rowsAffected;
            //返回
            try
            {
                 //保存,并缓存
                Session["currentObject"] = project.Save();//====Session
                //标记设置成功,就是说数据有改变
                rowsAffected = 1;
            }
                //权限异常(559)
            catch (Csla.Validation.ValidationException ex)
            {
                //字符串制造对象
                System.Text.StringBuilder message = new System.Text.StringBuilder();
                //先将获取的消息,添加进来
                message.AppendFormat("{0}<br/>", ex.Message);
                //有问题规则列表如果有一个,就直接显示
                if (project.BrokenRulesCollection.Count == 1)
                    message.AppendFormat("* {0}: {1}", project.BrokenRulesCollection[0].Property, project.BrokenRulesCollection[0].Description);
                else
                    //否则是多个,就用循环取出问题规则,主要是这个字符串加了<br/>,上面的无需加换行,否则是无需判断的
                    foreach (Csla.Validation.BrokenRule rule in project.BrokenRulesCollection)
                        message.AppendFormat("* {0}: {1}<br/>", rule.Property, rule.Description);
                //将问题显示
                this.ErrorLabel.Text = message.ToString();
                rowsAffected = 0;
            }
                //数据门户异常
            catch (Csla.DataPortalException ex)
            {
                this.ErrorLabel.Text = ex.BusinessException.Message;
                rowsAffected = 0;
            }
                //最后的异常
            catch (Exception ex)
            {
                this.ErrorLabel.Text = ex.Message;
                rowsAffected = 0;
            }
            return rowsAffected;
        }


        #endregion

        #region 事件方法

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                //设置授权
                ApplyAuthorizationRules();
            }
            else

                this.ErrorLabel.Text = string.Empty;
        }



        #endregion

        #region 数据控制

        #region ProjectDataSource
        /// <summary>
        /// 项目Detailview在删除的时候激发这个事件,这个事件在这里好像很难用上
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ProjectDataSource_DeleteObject( object sender, Csla.Web.DeleteObjectArgs e)
        {
            try
            {
                Project.DeleteProject(new Guid(e.Keys["Id"].ToString()));
                //清空是为了重新加载
                Session["currentObject"] = null; ////====Session
                e.RowsAffected = 1;
            }
            catch (Csla.DataPortalException ex)
            {
                this.ErrorLabel.Text = ex.BusinessException.Message;
                e.RowsAffected = 0;
            }
            catch (Exception ex)
            {
                this.ErrorLabel.Text = ex.Message;
                e.RowsAffected = 0;
            }
        }

        /// <summary>
        /// Detailview在插入的时候引发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ProjectDataSource_InsertObject(  object sender, Csla.Web.InsertObjectArgs e)
        {
            Project obj = GetProject();
            Csla.Data.DataMapper.Map(e.Values, obj, "Id");
            e.RowsAffected = SaveProject(obj);
        }

        /// <summary>
        /// 对象的一次数据绑定,会引发这个事件
        /// 要注意的一点是,如果你是点击新建进入这个页面的,在页面加载的时候也是会调用这个事件,为Detailview建立一个新的项目对象的
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ProjectDataSource_SelectObject(object sender, Csla.Web.SelectObjectArgs e)
        {
            e.BusinessObject = GetProject();
        }

        /// <summary>
        /// 当Detailview更新的时候激发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ProjectDataSource_UpdateObject(object sender, Csla.Web.UpdateObjectArgs e)
        {
            Project obj = GetProject();
            Csla.Data.DataMapper.Map(e.Values, obj);
            //调用保存方法,她扩展了异常的捕获
            e.RowsAffected = SaveProject(obj);
        }

        #endregion

        #region ResourcesDataSource
        /// <summary>
        /// ResourcesDataSource是
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ResourcesDataSource_DeleteObject( object sender, Csla.Web.DeleteObjectArgs e)
        {
            Project obj = GetProject();
            int rid = int.Parse(e.Keys["ResourceId"].ToString());
            obj.Resources.Remove(rid);
            e.RowsAffected = SaveProject(obj);
        }

        /// <summary>
        /// 当可编辑资源列表加载的时候引发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ResourcesDataSource_SelectObject( object sender, Csla.Web.SelectObjectArgs e)
        {
            Project obj = GetProject();
            //获得当前项目的所有资源
            e.BusinessObject = obj.Resources;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ResourcesDataSource_UpdateObject( object sender, Csla.Web.UpdateObjectArgs e)
        {
            //获得当前项目
            Project obj = GetProject();
            //获得更新的资源id
            int rid = int.Parse(e.Keys["ResourceId"].ToString());
            //通过父对象获得她的资源引用
            ProjectResource res = obj.Resources.GetItem(rid);
            //拷贝数据
            Csla.Data.DataMapper.Map(e.Values, res);
            //立即保存,
            e.RowsAffected = SaveProject(obj);
        }

        #endregion

        #region ResourceListDataSource
        /// <summary>
        /// ResourceListDataSource 是选择列表的资源,当载入一个对象的时候激发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ResourceListDataSource_SelectObject(  object sender, Csla.Web.SelectObjectArgs e)
        {
            //只读列表
            e.BusinessObject = ProjectTracker.Library.ResourceList.GetResourceList();
        }

        #endregion

        #region RoleListDataSource
        /// <summary>
        /// RoleListDataSource是在给一个项目现在资源后,配置这个资源的职务的时候的那个下拉列表框,同样在加载的时候激发
        /// 这个事件估计用的会很多,因为每一个被分配的资源记录都要计划一次她,来初始化对象的职务列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void RoleListDataSource_SelectObject( object sender, Csla.Web.SelectObjectArgs e)
        {
            //调用名只对列表
            e.BusinessObject = RoleList.GetList();
        }

        #endregion


        #endregion

        #region 界面控制
        #region Project DetailsView

        /// <summary>
        /// 在DetailsView控件初始化后,激发,用于填充数据
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void DetailsView1_ItemCreated(object sender, EventArgs e)
        {
            //校验模式,如果是录入模式这个录入才能成功,才是有意义的
            if (DetailsView1.DefaultMode == DetailsViewMode.Insert)
            {
                //调用私有方法,获取这个对象,这个也许是空值的,也许也是编辑的
                Project obj = GetProject();
                //将第二行的第二列的第一个控件的Text属性设置值,要知道是从0开始数的,而这里也没有什么控件,这里是Details的格子控件,没有名字用位置描述
                ((TextBox)DetailsView1.Rows[1].Cells[1].Controls[0]).Text = obj.Name;
                //将第三行的第二列的第一个控件的Text属性设置值
                ((TextBox)DetailsView1.Rows[2].Cells[1].Controls[0]).Text = obj.Started;
                //将第四行的第二列的第一个控件的Text属性设置值
                ((TextBox)DetailsView1.Rows[3].Cells[1].Controls[0]).Text = obj.Ended;

                //发现DetailsView1.中的名字为TextBox控件的设置Text属性
                ((TextBox)DetailsView1.FindControl("TextBox1")).Text = obj.Description;
            }
        }
        /// <summary>
        /// 在Details点击插入的之后,MSDN:在单击 DetailsView 控件中的“插入”按钮时,但在插入操作之后发生。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void DetailsView1_ItemInserted(object sender, DetailsViewInsertedEventArgs e)
        {
            Project project = GetProject();

            //如果不是新的则跳转
            if (!project.IsNew)
                Response.Redirect("ProjectEdit.aspx?id=" + project.Id.ToString());
        }
        /// <summary>
        /// 在单击 DetailsView 控件中的“更新”按钮时,但在更新操作之后发生。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void DetailsView1_ItemUpdated(  object sender, DetailsViewUpdatedEventArgs e)
        {
            ApplyAuthorizationRules();
        }

        /// <summary>
        /// 在单击 DetailsView 控件中的“删除”按钮时,但在删除操作之后发生。实际上这个事件是不会发生的,因为没有删除按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void DetailsView1_ItemDeleted( object sender, DetailsViewDeletedEventArgs e)
        {
            Response.Redirect("ProjectList.aspx");
        }

        #endregion

        #region Resource Grid

        /// <summary>
        /// 点击为项目添加一个资源按钮,切换视图
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void AddResourceButton_Click( object sender, EventArgs e)
        {
            this.MultiView1.ActiveViewIndex =(int)Views.AssignView;
        }

        /// <summary>
        /// GridView2是资源选择类表控件,当选择一个选项后激发此事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void GridView2_SelectedIndexChanged( object sender, EventArgs e)
        {
            //获取当前的项目对象
            Project obj = GetProject();
            try
            {
                //将选中的主键转换成整型,分配给自己
                //GridView2.SelectedDataKey.Value 代表,被选中项目的主键的值(559)
                obj.Resources.Assign(int.Parse( this.GridView2.SelectedDataKey.Value.ToString()));
                //调用私有保存方法,如果返回不是0,成功,则刷新视图1的资源列表,并切换回主页面
                //注销下面的if可以支持延迟保存

                //if (SaveProject(obj) > 0)
                //{
                    this.GridView1.DataBind();
                    this.MultiView1.ActiveViewIndex = (int)Views.MainView;
                //}
            }
                //如果你选中了已经存在的子对象(重复分配),Assign会发出一个异常,这个异常会在这里被捕获,处理的方法是将这个异常付给ErrorLabel显示给用户
            catch (InvalidOperationException ex)
            {
                ErrorLabel.Text = ex.Message;
            }
        }

        /// <summary>
        /// 在分配选择资源的时候点击取消,切回视图
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void CancelAssignButton_Click(object sender, EventArgs e)
        {
            this.MultiView1.ActiveViewIndex = (int)Views.MainView;
        }

        #endregion

        #endregion

    }
}
posted on 2009-10-06 10:23  冯瑞涛  阅读(1102)  评论(0编辑  收藏  举报