C# 网格中的交互控件

C# 网格中的交互控件,c#,asp.net,C#,Asp.net,我一直在设计一个网页上有网格的网站。网格中有多个组合框。这些组合框相互作用。即当一个值被用户更改时,另一个值发生更改或被禁用/启用等 我发现为了做到这一点,我必须大量使用FindControl。就像在一个组合框的selectedindexchanged事件中一样,我需要找到另一个组合框 这似乎是一种相当混乱的做事方式。这似乎也会让系统面临编译器无法找到的错误,比如说,如果组合框的id后来发生了更改 有人能告诉我有更好的方法吗?正是出于这个原因,我从ASP.NET转向在Silverlight中开发

我一直在设计一个网页上有网格的网站。网格中有多个组合框。这些组合框相互作用。即当一个值被用户更改时,另一个值发生更改或被禁用/启用等

我发现为了做到这一点,我必须大量使用FindControl。就像在一个组合框的selectedindexchanged事件中一样,我需要找到另一个组合框

这似乎是一种相当混乱的做事方式。这似乎也会让系统面临编译器无法找到的错误,比如说,如果组合框的id后来发生了更改


有人能告诉我有更好的方法吗?

正是出于这个原因,我从ASP.NET转向在Silverlight中开发并利用其MVVM模式。即使使用ASP.NET的GridView项目模板,也无法直接将每个项目绑定到、了解或引用同一模板中的其他项目。您的代码必须在某种程度上(通常是最完整的)了解视图控件的组合层次结构

下面是您可以做些什么来更接近“更好的绑定世界”。您仍然可以将组合框绑定到相同的列表数据源,但在创建每行项/控件时,您会将每个项与对象(即标记项)关联。然后,在控件的事件处理中,您将检索与引发事件的控件关联的标记项关联的其他控件,并对它们执行您将要执行的操作


我知道,这不是最好的主意,只是我一时兴起。也许当我有时间对此进行更多思考时,我可以更新这篇文章。

我有一个web应用程序,它还广泛使用各种FindControl排列,以完成您描述的内容。尽管它很脆弱(未经测试请勿更改控件ID),但通过一些实用程序功能,它可以稍微减轻一些麻烦。下面是我使用的所有FindControl类型函数——这至少可以帮助您

/// <summary>
/// Recursively searches for a control within the heirarchy of a given control.
/// </summary>
/// <param name="root">The control to search within.</param>
/// <param name="id">The ID of the control to find.</param>
/// <returns>The Control object of the found control, or null if the control isn't found.</returns>
public static Control FindControlRecursive(Control root, string id)
{
    if (root.ID == id) return root;

    foreach (Control c in root.Controls)
    {
        Control t = FindControlRecursive(c, id);
        if (t != null) return t;
    }

    return null;
}

/// <summary>
/// Recursively searches for a control within the heirarchy of a given control using the Client ID
/// of the control. Calling this too early in the lifecycle may not behave as expected.
/// </summary>
/// <param name="root">The control to search within.</param>
/// <param name="clientID">The Client ID of the control to find.</param>
/// <returns>The Control object of the found control, or null if the control isn't found.</returns>
public static Control FindControlRecursiveByClientID(Control root, string clientID)
{
 if (0 == String.Compare(root.ClientID, clientID, true)) return root;

 foreach (Control c in root.Controls)
 {
  Control t = FindControlRecursiveByClientID(c, clientID);
  if (t != null) return t;
 }

 return null;
}

/// <summary>
/// Recursively searches for a group of controls within the heirarchy of a given control tree using the ID
/// of the control.
/// </summary>
/// <param name="root">The control tree to search within.</param>
/// <param name="id">The ID of the control to find.</param>
/// <returns>
/// A collection of the found controls. The collection will be empty if none are found.
/// </returns>
public static List<Control> FindControlsRecursive(Control root, string id)
{
 List<Control> collection = new List<Control>();
 FindControlRecursive(root, id, collection);
 return collection;
}

private static void FindControlRecursive(Control root, string id, List<Control> collection)
{
 foreach (Control c in root.Controls)
 {
  if (0 == String.Compare(c.ID, id, true)) collection.Add(c);
  else FindControlRecursive(c, id, collection);
 }
}

/// <summary>
/// Recursively searches for a control within the heirarchy of a given control using the type
/// of the control.
/// </summary>
/// <typeparam name="T">The type of the control to find.</typeparam>
/// <param name="root">The control to search within.</param>
/// <returns>
/// The Control object of the found control, or null if the control isn't found.
/// </returns>
public static T FindControlRecursiveByType<T>(Control root)
 where T : Control
{
 if (root is T) return (T)root;
 foreach (Control c in root.Controls)
 {
  Control t = FindControlRecursiveByType<T>(c);
  if (t != null) return (T)t;
 }
 return null;
}

/// <summary>
/// Recursively searches for a set of controls within the heirarchy of a given control using the type
/// of the control.
/// </summary>
/// <typeparam name="T">The type of the control to find.</typeparam>
/// <param name="root">The control to search within.</param>
/// <returns>
/// A generic List object containing the controls found, or an empty List of none were found.
/// </returns>
public static List<T> FindControlsRecursiveByType<T>(Control root)
 where T : Control
{
 List<T> collection = new List<T>();
 FindControlRecursiveByType<T>(root, collection);
 return collection;
}

private static void FindControlRecursiveByType<T>(Control root, List<T> collection)
 where T : Control
{
 foreach (Control c in root.Controls)
 {
  if (c is T) collection.Add((T)c);
  else FindControlRecursiveByType<T>(c, collection);
 }
}
//
///递归搜索给定控件继承权内的控件。
/// 
///要在其中搜索的控件。
///要查找的控件的ID。
///找到的控件的控件对象,如果找不到该控件,则为null。
公共静态控件FindControlRecursive(控件根,字符串id)
{
if(root.ID==ID)返回root;
foreach(root.Controls中的控件c)
{
控件t=FindControlRecursive(c,id);
如果(t!=null)返回t;
}
返回null;
}
/// 
///使用客户机ID在给定控件的继承权限内递归搜索控件
///控制的一部分。在生命周期中过早调用此功能可能不会按预期进行。
/// 
///要在其中搜索的控件。
///要查找的控件的客户端ID。
///找到的控件的控件对象,如果找不到该控件,则为null。
公共静态控件FindControlRecursiveByClientID(控件根,字符串clientID)
{
if(0==String.Compare(root.ClientID,ClientID,true))返回root;
foreach(root.Controls中的控件c)
{
控件t=FindControlRecursiveByClientID(c,clientID);
如果(t!=null)返回t;
}
返回null;
}
/// 
///使用ID在给定控件树的继承权内递归搜索一组控件
///控制的一部分。
/// 
///要在其中搜索的控件树。
///要查找的控件的ID。
/// 
///找到的控件的集合。如果找不到集合,则集合将为空。
/// 
公共静态列表FindControlsRecursive(控件根,字符串id)
{
列表集合=新列表();
FindControlRecursive(根、id、集合);
回收;
}
私有静态void FindControlRecursive(控件根、字符串id、列表集合)
{
foreach(root.Controls中的控件c)
{
if(0==String.Compare(c.ID,ID,true))collection.Add(c);
else FindControlRecursive(c、id、集合);
}
}
/// 
///使用类型在给定控件的继承权限内递归搜索控件
///控制的一部分。
/// 
///要查找的控件的类型。
///要在其中搜索的控件。
/// 
///找到的控件的控件对象,如果找不到该控件,则为null。
/// 
公共静态T FindControlRecursiveByType(控件根)
其中T:控制
{
如果(root是T)返回(T)root;
foreach(root.Controls中的控件c)
{
控件t=FindControlRecursiveByType(c);
如果(t!=null)返回(t)t;
}
返回null;
}
/// 
///使用类型在给定控件的继承权限内递归搜索一组控件
///控制的一部分。
/// 
///要查找的控件的类型。
///要在其中搜索的控件。
/// 
///包含找到的控件的常规列表对象,或未找到任何控件的空列表。
/// 
公共静态列表FindControlsRecursiveByType(控件根)
其中T:控制
{
列表集合=新列表();
FindControlRecursiveByType(根,集合);
回收;
}
私有静态void FindControlRecursiveByType(控件根、列表集合)
其中T:控制
{
foreach(root.Controls中的控件c)
{
如果(c是T)集合,则添加((T)c);
else FindControlRecursiveByType(c,集合);
}
}

用事件来做通知怎么样?

这些都很混乱

这是一个非常简单和优雅的解决方案。假设网格需要在包含3列的表中显示数据。数据来自具有以下结构的对象:

[Serializable]
public class Foo
{
    public string Bar1 { get; set; }
    public string Bar2 { get; set; }
    public string Bar3 { get; set; }
}
然后,您的用户控件将具有以下标记:

标记(GridDisplayRow.ascx):


注意所有的div标记。孩子们的分区是浮动的。。。使它们并排显示

代码隐藏(GridDisplayRow.ascx.cs):

类GridDisplayRow:UserControl
{
公共事件处理程序发生了什么事情;
受保护的无效页面加载(对象发送方、事件参数e)
{
//用一些东西初始化下拉列表;
}
//这是我们处理内部事件的地方
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="GridDisplayRow.ascx.cs" Inherits="GridDisplayRow" %>
<div>
    <div class="cell">
        <asp:TextBox id="TxtProperty1" runat="server"/>
    </div>
    <div class="cell">
        <asp:DropDownList ID="DDLProperty2" runat="server" OnSelectedIndexChanged="DDLProperty2_OnSelectedIndexChanged" AutoPostBack="true">
        </asp:DropDownList>
    </div>
    <div class="cell">
        <input type="radio" id="RadProperty3" runat="server">
    </div>
</div>
class GridDisplayRow:UserControl
{
   public event EventHandler<System.EventArgs> SomethingHappened;

   protected void Page_Load(object sender, EventArgs e)
   {
       //Initialize the drop down with something;
   }

   //this is where we handle internal events generated by children controls.
   //Eg: the drop down's index changed.
   protected void DDLProperty2_OnSelectedIndexChanged(object sender, EventArgs e)
   {
       //we update some other child control in this...
       this.TxtProperty1.Text = this.DDLProperty2.Value;

       //and maybe we want to signal the page that some event happened
       if(SomethingHappened != null)
       {
          //Notify the page that SomethingHappened event occured
          SomethingHappened(this, EventArgs.Empty);
       } 
   }

   //This is where the binding happens
   public object BindingObject
   {
      set
      {
           Foo temp = (Foo)value;
           this.TxtProperty1.Text = temp.Bar1;
           this.DDLProperty2.Value = temp.Bar2;
           this.RadProperty3.Value = temp.Bar3;

           this.ViewState["Foo"] = temp;   
      }
   }
}
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %>
<%@ Register src="GridDisplayRow.ascx" tagname="GridRow" tagprefix="ctrl" %>

<asp:GridView ID="GridView1" runat="server">
    <Columns>
        <asp:TemplateField>
            <HeaderTemplate>
                <div>
                    <div class="header cell">Header 1</div>
                    <div class="header cell">Header 2</div>
                    <div class="header cell">Header 3</div>
                </div>
            </HeaderTemplate>
            <ItemTemplate>
                <ctrl:GridRow ID="Row" runat="server" BindingObject='<%# Container.DataItem %>' OnSomethingHappened="Row_SomethingHappened" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>