0

我有一个具有 2 个属性的自定义类的通用列表。这些属性存储了一个表单和另一个表单之间的关系。该列表被构造为分层列表(父/子)关系。我想要做的是根据将传递给函数的父表单引用获取所有表单的列表。我认为解决此问题的最佳方法是使用递归方法进行 LINQ 查询。我相信有人可以为我指明正确的方向

这是列表中使用的类

class FormStack    {

    #region Declares

    private Form _form;
    private Form _parent;

    #endregion

    #region Constructor

    static FormStack()
    {
    }

    #endregion

    public Form Form
    {
        get { return _form; }
        set { _form = value; }
    }

    public Form Parent
    {
        get { return _parent; }
        set { _parent = value; }
    }

}

所以我希望能够调用一个方法并将表单引用传递给该函数并获取与该父级相关的所有子表单。

这是我一直在绊倒的一些代码

// create a lookup list
var list = formStack.ToLookup( p => object.ReferenceEquals( p.Parent, parent ) );

// create a function
Func<IEnumerable<Form>, IEnumerable<Form>> recurse = null;
recurse = qs =>
{
    return
        qs
            .Concat(
                from q in qs
                from q2 in recurse( list[] )
                select q2 );
};

// filter the list
var children = recurse( list[parent] ).ToList();

我有一个具有标准 CRUD 功能的 winform 应用程序。假设有一个客户列表,每个客户可以有多个地址,每个地址都有多个建筑物,我构建表格的方式是有一个客户列表,从这个列表中你可以打开一个详细的表格一个特定的客户。此表格包含客户的详细信息和列表中的所有地址。此列表允许用户现在在列表中选择一个地址并打开包含建筑物列表等的地址详细信息表单......我的问题是我想关闭该客户的客户详细信息和所有相关表单. 我的想法是保持表格之间的关系,但也许我有更好的方法???

4

2 回答 2

0

好的,在我看来,您有两个问题。一个是语法错误(recurse(list[])是错误的),但另一个是您的 FormStack 并不是真正的堆栈。它只是两种形式,没有办法创建递归链。我想你想要这个:

public class FormStack : IEnumerable<Form> // or just implement SelectMany
{    
    public Form Form { get; set; }
    public FormStack Parent { get; set; }  
    //implement IEnumerable<Form> or the SelectMany method
}

然后我认为您可以这样做,但这似乎是一件尴尬的事情:

Func<FormStack, IEnumerable<Form>> recurse = qs =>
{
    return from q in qs
           select (new[] { qs.Form }).Concat(recurse(qs.Parent));
};

var list = recurse(formStack).ToList();

那是如果您坚持使用查询语法。

但是,如果我是你,我会忘记所有这些并实施 anIEnumerator<Form>来为你做这一切:

public class FormStack : IEnumerable<Form> 
{    
    public Form Form { get; set; }
    public FormStack Parent { get; set; }  
    public IEnumerator IEnumerable:GetEnumerator() 
    { 
        return (IEnumerator)GetEnumerator();
    }
    public IEnumerator<Form> GetEnumerator() 
    { 
        return new FormStackEnumerator(this);
    }
}
public class FormStackEnumerator : IEnumerator<Form>
{
    private FormStack _stack;
    private FormStack _first;
    public Form Current { get { return _stack.Form; } }
    object IEnumerator.Current { get { return Current; } }

    public FormStackEnumerator(FormStack stack)
    {
        _stack = stack;
        _first = stack;
    }
    public bool MoveNext()
    {
        if (_stack.Parent == null)
        {
            return false;
        }
        _stack = _stack.Parent;
        return true;
    }
    public void Reset() { _stack = _first; }
    void IDisposable.Dispose() { }
}

那么你需要在你的主代码中做的就是:

var list = new List<Form>();
foreach (var node in formStack)
{
    list.Add(node.Form);
}

顺便说一句,我只是查找了 Form 类(我不是 WinForms 开发人员)并且 Forms 本身有一个 Parent 成员。因此,您实际上不需要将它们包装在节点类型的构造中;他们已经是节点!这让一切变得简单:

var list = new List<Form>();

Action<Control> recurse = target =>
{
    var form = target as Form;
    if (form != null)
    {
        list.Add(form);
        recurse(target.Parent);
    }
}
于 2012-11-05T07:17:25.743 回答
0

这是我编造的:

为所有表单创建一个基本表单:

public class MyFormBase : Form
{
    public MyFormBase()
    {
        FormRepository.RegisterForm(this);
    }

    public MyFormBase(MyFormBase parent)
        : this()
    {
        Parent = parent;
    }

    public MyFormBase Parent { get; set; }
}

每个表单只能有一个在构造函数中传递的父级。

创建一个存储库(或类似的东西)来存储您的表单->我不想将所有子项存储在表单本身中

//infrastructure - simulated with a static class
public static class FormRepository
{
    private static List<MyFormBase> _allForms = new List<MyFormBase>();

    public static void RegisterForm(MyFormBase form)
    {
        _allForms.Add(form);
    }

    public static void CloseFormAndChildren(MyFormBase form)
    {
        _allForms.Where(x => x.Parent.Equals(form)).ToList().ForEach(x => CloseFormAndChildren(x));
        form.Close();
    }
}

在您要关闭的任何表单(包括孩子)上调用 CloseFormAndChildren。这可以在结束事件中调用...

于 2012-11-06T15:58:04.993 回答