1

以下のコードには、ツリーのノードのタグに格納されているAccessIdのリストがあります。それらのタグがリストにあるノード(または子ノード)を確認するにはどうすればよいですか?

List<AccessFieldSet> AccessList = new List<AccessFieldSet>();
private void GetRolesAccessData(Int32 RolesId)
{            
    C_RolesUsers Db = new C_RolesUsers();
    AccessList = Db.GetRolesAccessData(RolesId);
    foreach (AccessFieldSet Afs in AccessList)
    {
        foreach (TreeNode node in TreeRoles.Nodes)
        {
            if (node.Tag == Afs.AccessId.ToString())
            {
                //Check Node is true ?
            }
            GetTagChildren(node);
        }
    }
}

private void GetTagChildren(TreeNode Node)
{
    TreeNode ChNode = null;
    //TreeFieldSet nodeCat = (TreeFieldSet)Node.Tag;
    //Int32 nodeCat = (Int32)Node.Tag;
    foreach (AccessFieldSet Afs in AccessList)
    {
        if (Afs.AccessId.ToString() == Node.Tag)
        {
            //Check Node is true ?
            GetTagChildren(ChNode);
        }
    }
}

コードを次のように編集します:

List<AccessFieldSet> AccessList = new List<AccessFieldSet>();
private void GetRolesAccessData(Int32 RolesId)
{            
    C_RolesUsers Db = new C_RolesUsers();
    AccessList = Db.GetRolesAccessData(RolesId);
    for (int i = 0; i < TreeRoles.Nodes.Count; i++)
    {
        CheckedSelectedNodes(i, TreeRoles.Nodes, AccessList);
    }
}

private void CheckedSelectedNodes(Int32 i, TreeNodeCollection nodes, List<AccessFieldSet> AccessList)
{
    TreeNode node = nodes[i];
    for (int j = 0; j < AccessList.Count; j++)
    {
        foreach (AccessFieldSet Afs in AccessList)
        {
            if ((int)node.Tag == Afs.AccessId)
            {
                node.Checked = true;
            }
        }
    }
}

新しいコードで、ノードのタグがAccessListにあるノードを確認できます。ChildNodes(ノードの子)のコードを変更するにはどうすればよいですか?

4

1 に答える 1

1

再帰を使用して、これを非常にエレガントに行うことができます。

List<AccessFieldSet> accessList = new List<AccessFieldSet>(); 

private void GetRolesAccessData(Int32 RolesId) 
{             
    C_RolesUsers Db = new C_RolesUsers(); 
    accessList = Db.GetRolesAccessData(RolesId);
    foreach (TreeNode node in TreeRoles.Nodes)
    {
        CheckNodeRecursively(node, accessList);
    } 
} 

private void CheckNodeRecursively(TreeNode node, List<AccessFieldSet> accessList) 
{
    // Note: You don't need the for loop through 'j'.
    foreach (AccessFieldSet afs in accessList) 
    { 
        if ((int)node.Tag == afs.AccessId) 
        { 
            node.Checked = true; 
        } 
    }
    foreach (TreeNode childNode in node.Nodes)
    {
        CheckNodeRecursively(childNode, accessList);
    }
} 

この種のことを頻繁に行う場合は、再帰をユーティリティメソッドに分解し、アクションを使用して「ノードごとに動作する」ロジックを変更することができます。例えば:

public static void ActOnAllRecursively(this TreeNodeCollection nodes, Action<TreeNode> action)
{
    foreach (TreeNode node in nodes)
    {
        ActOnRecursively(node, action);
    }
}

public static void ActOnRecursively(this TreeNode node, Action<TreeNode> action)
{
    action(node);
    foreach (TreeNode node in node.Nodes)
    {
        ActOnRecursively(node);
    }
}

次に、コードは次のようになります。

List<AccessFieldSet> accessList = new List<AccessFieldSet>(); 

private void GetRolesAccessData(Int32 RolesId) 
{             
    C_RolesUsers Db = new C_RolesUsers(); 
    accessList = Db.GetRolesAccessData(RolesId);
    TreeRoles.Nodes.ActOnAllRecursively((node) =>
    {
        foreach (AccessFieldSet afs in accessList) 
        { 
            if ((int)node.Tag == afs.AccessId) 
            { 
                node.Checked = true; 
            } 
        } 
    });
}

そして最後に、LINQに夢中になり、宣言型のスタイルでアプリ固有のコードを記述できます。

List<AccessFieldSet> accessList = new List<AccessFieldSet>(); 

private void GetRolesAccessData(Int32 RolesId) 
{             
    C_RolesUsers Db = new C_RolesUsers(); 
    accessList = Db.GetRolesAccessData(RolesId);
    TreeRoles.Nodes.ActOnAllRecursively((node) =>
    {
        node.Checked = accessList.Any(afs => afs.AccessId == (int)node.Tag);
    });
}
于 2012-06-06T05:29:43.943 に答える