ASP.NET 2.0 TreeView - OnSelectedNodeChanged не запускается в пользовательском элементе управления - PullRequest
3 голосов
/ 22 июня 2010

У меня есть небольшой пользовательский элемент управления, определенный как:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="CompanyTree.ascx.cs" Inherits="RivWorks.Web.UserControls.CompanyTree" %>

<div class="PrettyTree">
    <asp:TreeView runat="server" 
                  ID="companyTree" 
                  OnSelectedNodeChanged="SelectedNodeChanged" 
                  OnAdaptedSelectedNodeChanged="SelectedNodeChanged" >
    </asp:TreeView>

    <asp:Label runat="server" ID="currentParentID" Text="" Visible="false" />
    <asp:Label runat="server" ID="currentCompanyID" Text="" Visible="false" />
    <asp:Label runat="server" ID="currentExpandDepth" Text="" Visible="false" />
    <asp:Label runat="server" ID="currentValuePath" Text="" Visible="false" />
    <asp:Label runat="server" ID="currentParentValuePath" Text="" Visible="false" />
    <asp:Label runat="server" ID="currentCompanyUser" Text="" Visible="false" />
</div>

По какой-то причине события OnSelectedNodeChanged и OnAdaptedSelectedNodeChanged не запускаются, когда я нажимаю на узел в дереве. Я гуглил в течение последнего часа и не нашел ничего плохого.

Вот мои обработчики событий в коде позади.

#region Event Handlers  
protected void Page_Load(object sender, EventArgs e)  
{  
    if (!IsPostBack)  
    {  
        LoadCompanyTree();

        TreeNode currentNode = companyTree.SelectedNode;
        CompanyID = currentNode.Value;
        ValuePath = currentNode.ValuePath;
        if (currentNode.Parent != null)
        {
            ParentCompanyID = currentNode.Parent.Value;
            ParentValuePath = currentNode.Parent.ValuePath;
        }
        else
        {
            ParentCompanyID = "";
            ParentValuePath = "";
        }
        ExpandDepth = currentNode.Depth.ToString();

        LoadCompany();
    }
}
protected void SelectedNodeChanged(object sender, EventArgs e)
{
    TreeNode currentNode = companyTree.SelectedNode;
    CompanyID = currentNode.Value;
    ValuePath = currentNode.ValuePath;
    if (currentNode.Parent != null)
    {
        ParentCompanyID = currentNode.Parent.Value;
        ParentValuePath = currentNode.Parent.ValuePath;
    }
    else
    {
        ParentCompanyID = "";
        ParentValuePath = "";
    }
    ExpandDepth = currentNode.Depth.ToString();

    LoadCompany();
}
#endregion

Я также включил код для построения дерева. Моя структура данных основана на http://articles.sitepoint.com/article/hierarchical-data-database.

private void LoadCompanyTree()
{
    DataTable dtTree = RivWorks.Data.Companies.GetTree();
    companyTree.Nodes.Clear();
    companyTree.Nodes.Add(RivWorks.Web.Tree.BuildTree(dtTree, Page));
    companyTree.ExpandDepth = 1;
    companyTree.Nodes[0].Selected = true;
    companyTree.Nodes[0].Select();

    companyTree.ShowLines = true;
    companyTree.RootNodeStyle.ImageUrl = Page.ResolveUrl(@"~/images/tree/root.png");
    companyTree.ParentNodeStyle.ImageUrl = Page.ResolveUrl(@"~/images/tree/parent.png");
    companyTree.LeafNodeStyle.ImageUrl = Page.ResolveUrl(@"~/images/tree/leaf.png");
    companyTree.SelectedNodeStyle.Font.Bold = true;
    companyTree.SelectedNodeStyle.Font.Italic = true;

    if (CompanyID.Length > 0)
    {
        for (int i = 0; i < companyTree.Nodes.Count; i++)
        {
            if (companyTree.Nodes[i].Value.Equals(CompanyID, StringComparison.CurrentCultureIgnoreCase))
            {
                companyTree.ExpandDepth = companyTree.Nodes[i].Depth;
                ValuePath = companyTree.Nodes[i].ValuePath;
                companyTree.Nodes[i].Selected = true;
                companyTree.Nodes[i].Select();
            }
        }
    }
}


internal static TreeNode BuildTree(DataTable dtTree, System.Web.UI.Page myPage)
{
    int left = 0;
    int right = 0;
    int index = 0;
    Stack<int> rightStack = new Stack<int>();
    Stack<TreeNode> treeStack = new Stack<TreeNode>();
    TreeNode rootNode = new TreeNode(dtTree.Rows[index]["CompanyName"].ToString(), dtTree.Rows[index]["CompanyID"].ToString());

    while (index < dtTree.Rows.Count)
    {
        left = Convert.ToInt32(dtTree.Rows[index]["left"]);
        right = Convert.ToInt32(dtTree.Rows[index]["right"]);

        if (rightStack.Count > 0)
        {
            while (rightStack.Peek() < right)
            {
                rightStack.Pop();
                treeStack.Pop();
            }
        }
        if (treeStack.Count == 0)
        {
            treeStack.Push(rootNode);
        }
        else
        {
            TreeNode treeNode = new TreeNode(dtTree.Rows[index]["CompanyName"].ToString(), dtTree.Rows[index]["CompanyID"].ToString());
            treeStack.Peek().ChildNodes.Add(treeNode);
            treeStack.Push(treeNode);
        }

        rightStack.Push(right);
        index++;
    }

    return rootNode;
}

Когда я помещаю это в ASPX-страницу, она работает нормально. Когда я переместил его в пользовательский элемент управления ASCX, событие больше не запускается! Какие-либо советы / предложения по организации мероприятия?

ТИА


Примечание: Я использую Адаптеры дружественного управления CSS, найденные на CodePlex. http://cssfriendly.codeplex.com/workitem/5519?PendingVoteId=5519 - отчет об ошибке события, которое не вызывается в пользовательском контроле (.ascx). Я добавил предложенный код плюс еще, и он все еще не срабатывает.

<MasterPage>
  <Page>
    <ContentHolder>
      <User Control>    <-- this should handle the event!
        <TreeView with CSSFriendly Adapter>

код в адаптере:

public void RaiseAdaptedEvent(string eventName, EventArgs e)
{
    string attr = "OnAdapted" + eventName;
    if ((AdaptedControl != null) && (!String.IsNullOrEmpty(AdaptedControl.Attributes[attr])))
    {
        string delegateName = AdaptedControl.Attributes[attr];
        Control methodOwner = AdaptedControl.Parent;
        MethodInfo method = methodOwner.GetType().GetMethod(delegateName);

        if (method == null)
        {
            methodOwner = AdaptedControl.Page;
            method = methodOwner.GetType().GetMethod(delegateName);
        }

        // 2010.06.21 - keith.barrows - added to (hopefully) handle User Control (ASCX) coding...
        // http://forums.asp.net/t/1249501.aspx
        if (method == null)
        {
            Control parentUserControl = FindParentUserControl(AdaptedControl.Parent);
            if (parentUserControl != null)
            {
                methodOwner = parentUserControl;
                method = methodOwner.GetType().GetMethod(delegateName);
            }
        }

        // 2010.06.21 - keith.barrows - added to (hopefully) handle User Control (ASCX) coding...
        // http://cssfriendly.codeplex.com/workitem/5519?ProjectName=cssfriendly
        if (method == null)
        {
            methodOwner = AdaptedControl.NamingContainer;
            method = methodOwner.GetType().GetMethod(delegateName);
        }

        if (method == null)
        {
            methodOwner = AdaptedControl.Parent;
            method = methodOwner.GetType().GetMethod(delegateName);
        }

        if (method != null)
        {
            object[] args = new object[2];
            args[0] = AdaptedControl;
            args[1] = e;
            method.Invoke(methodOwner, args);
        }
    }
}

private Control FindParentUserControl(Control control)
{
    if (control.Parent == null)
        return null;
    if (control.Parent is UserControl)
        return control.Parent;
    return FindParentUserControl(control.Parent);
}

Мне не хватает делегата или определения события? Адаптированный элемент управления ПРОСТО НЕ НАЙДЕТ метод для вызова!

Ответы [ 2 ]

1 голос
/ 07 февраля 2011

Я обнаружил, что у CSS Friendly есть некоторые проблемы с вызовом защищенных методов.Вот как я могу это исправить:

В классе WebControlAdapterExtender, метод WebControlAdapterExtender (строка 161) я добавил эту строку:

if (method == null)
{
method = methodOwner.GetType().GetMethod(delegateName, BindingFlags.Instance | 
                   BindingFlags.NonPublic);
}

и работает для меня.Надеюсь, это поможет.

1 голос
/ 23 июня 2010

Совершенно случайно я нашел решение, которое действительно работает. Не спрашивайте меня, почему, но я очень хочу узнать!

В коде моей страницы ASPX я добавил подпись этого метода:

protected void SelectedNodeChanged(object sender, EventArgs e)
{
}

И теперь событие RaiseAdaptedEvent находит обработчик события в файле ASCX !!

Прежде чем я отмечу это как ответ - кто-нибудь знает, почему это будет работать таким образом?

...