我有一个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都标记有相应的Operand。当选择TreeView中的项目时,带标签的项目将显示在面板中,以便您可以更改其属性。例如。当我选择一个项目时,会出现一个复选框,您可以在其中设置IsNegated值。我已经成功使用以下方法将该控件绑定到Operand对象:
negateCheckBox.DataBindings.Add("Checked", requirementTree.SelectedNode.Tag, "IsNegated");
单击复选框会适当地更新基础数据,但不会导致TreeView刷新其数据,因此,即使该项目的ToString()方法的返回值已更改(它现在带有“ NEGATIVE”前缀),因为TreeNode已经使用该字符串创建,所以不会更新。
我也有一些“添加”和“删除”按钮,它们在TreeView中创建其他节点并将其删除,但是所有这些都是手动操作的-更新基础数据结构,然后重建整个TreeView(这将导致视图刷新,这样我就可以验证我的其他绑定是否正常工作。
我需要采取什么步骤,以便不手动填充TreeView,而是将其完全绑定到我的数据结构,以便立即反映出这样的变化?似乎有很多方法可以绑定WinForms中的数据,但我不清楚哪种方法适用于哪种情况。
非常感谢您的帮助!
答案 0 :(得分: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()函数手动处理了并手动跟踪/销毁它们。
这似乎实现了我的大部分目标,所以除非有人有其他想法,否则我将坚持下去。