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