【问题标题】:How can I have a WinForms TreeView update when the tagged objects change?标记对象更改时如何更新 WinForms TreeView?
【发布时间】:2019-07-21 09:53:27
【问题描述】:

我有一个 WinForms TreeView 来表示我的计算器数据。当我读入我的数据时,我创建了我的 TreeView 并用相应的对象标记每个 TreeView 节点。下面是一个示例 TreeView。

SUM
    SUM
        TIMES
            UnitsSold
            UnitPrice
        IncomeFromContracts
    NEGATIVE SUM
        Rent
        Wages
        TIMES
            UnitsSold
            UnitMaterialCost

我从以下数据结构创建 TreeView:

class Operand {
    bool IsNegated {get; set;}
}

class Operator : Operand {
    enum OperatorEnum { SUM, DIFFERENCE, TIMES }
    OperatorEnum MyEnum {get; set;}
    IList<Operand> Children {get; set;}
}

class VariableName : Operand {
    string Name {get; set;}
}

每个 TreeNode 都使用相应的操作数进行标记。当 TreeView 中的项目被选中时,标记的项目会显示在面板中,以便您可以更改其属性。例如。当我选择一个项目时,您会看到一个复选框,您可以在其中设置 IsNegated 值。我已经成功地将该控件绑定到 Operand 对象,使用:

negateCheckBox.DataBindings.Add("Checked", requirementTree.SelectedNode.Tag, "IsNegated");

单击复选框会适当地更新基础数据,但不会导致 TreeView 刷新其数据,因此即使项目的 ToString() 方法的返回值已更改(它现在以“NEGATIVE”为前缀),因为已经使用该字符串创建了 TreeNode,所以它不会更新。

我还有一些“添加”和“删除”按钮,它们可以在 TreeView 中创建其他节点并删除它们,但这些都是手动操作的——更新底层数据结构,然后重建整个 TreeView(这会导致视图刷新,这样我就可以验证我的其他绑定是否正常工作)。

我需要采取哪些步骤才能不手动填充 TreeView,而是完全绑定到我的数据结构,以便立即反映此类更改?似乎有很多方法可以在 WinForms 中绑定数据,我不清楚哪些适用于哪些情况。

非常感谢您的帮助!

【问题讨论】:

  • TreeView 节点不支持数据绑定,所以需要手动处理。您可以find the node with tag 并反映更改。
  • 也不要依赖 UI 事件,点击按钮,依赖数据结构的事件。

标签: c# winforms treeview


【解决方案1】:

根据 Reza 关于 TreeView 不支持数据绑定的评论,我想出了一个合理的解决方法。

每个“模型”类都实现 INotifyPropertyChanged 并在其任何属性发生更改时引发事件。

class Operand : INotifyPropertyChanged
{
    public bool IsNegated
    {
        get { return m_isNegated; }
        set { m_isNegated = value; RaisePropertyChanged(); }
    }
    private bool m_isNegated = false;

    private void RaisePropertyChanged([CallerMemberName]string prop = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
    }
}

然后我添加了一个虚拟控制器,它将模型链接到 TreeView 节点:

public class OperandTreeNodeController

{
    private Requirement m_model;
    private TreeNode m_view;

    public OperandTreeNodeController(Requirement model, TreeNode view)
    {
        m_model = model;
        m_view = view;

        m_model.PropertyChanged += Model_PropertyChanged;
    }

    private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        m_view.Text = m_model.ToString();
    }
}

现在,每当我创建 TreeNode 时,我也会创建一个控制器。这里有一点内存“泄漏”,因为这些可以继续创建并附加到模型的 PropertyChanged 事件中,而垃圾收集器可能永远不会清理它们,但我已经通过添加 Destroy() 函数在我的代码中手动处理了并手动跟踪/销毁它们。

这似乎实现了我的大部分目标,所以除非有人有其他想法,否则我会坚持下去。

【讨论】:

    猜你喜欢
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多