项目原方案用的是比较简单的方案,绑定后,要更新显示,对绑定类先清除子节点再加上新的节点,更新到.net6后发现运行中内存消耗不断增加。经排查问题出在这一段,怀疑childNodes.Clear()后,原引用没有释放。原因不明,有了解的高手请指点。
fatherNode.ChildNodes.Clear();
foreach (Weather v in weathers.Values) //weathers是数据来源
{
SubEq subNode = new()
{
Display = v.Config.Dislplay + ":" + v.StrValue//显示新内容
};
fatherNode.ChildNodes.Add(subNode);
}
为解决以上问题,采样INotifyPropertyChanged接口方案。
前端代码:
<TreeView x:Name="TvRealTimeData" Padding="1,1,5,1">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ChildNodes}">
<TextBlock Text="{Binding Display}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True"></Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
后台代码:
/// <summary>
/// 绑定ViewTree,记录设备状态
/// </summary>
private readonly List<Equipment> EquipmentTree = new();
public WpfMain()
{
//初始化EquipmentTree省略
InitializeComponent();
TvRealTimeData.ItemsSource = EquipmentTree;//绑定界面树
}
/// <summary>
/// 控件绑定EquipmentTree,更新属性即可
/// </summary>
/// <param name="weathers"></param>
private void ShowRealData(Weathers weathers)
{
Equipment fatherNode = EquipmentTree.Find(x => x.Address == weathers.Address);
try
{
foreach (var n in fatherNode.ChildNodes)
{
var v = weathers.Values.Find(x => x.Config.Index == n.Index);
n.Display = v.Config.Dislplay + ":" + v.StrValue;
}
}
catch (Exception)
{
}
}
要绑定的Equipmnet类
public class Equipment
{
public byte Address { get; set; }
public string Display { get; set; }
public ObservableCollection<SubEq> ChildNodes { get; set; } = new();
}
/// <summary>
/// 设备下的子设备,用于TreeView数据展示,有命令返回时动态删除重建,不适合保存其他数据
/// </summary>
public class SubEq : INotifyPropertyChanged
{
private string _Display;
public uint Index { get; set; }
public string Display { get => _Display; set => UpdateProperty(ref _Display, value); }
public List<SubEq> ChildNodes { get; set; } = new();//未使用,仅防止编译器提示
/// <summary>
/// 属性改变事件句柄
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// 属性改变事件
/// </summary>
/// <param name="propertyName">已更改属性的名称,null参数指示所有属性已更改</param>
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void UpdateProperty<T>(ref T properValue, T newValue, [CallerMemberName] string propertyName = "")
{
if (Equals(properValue, newValue))
{
return;
}
properValue = newValue;
OnPropertyChanged(propertyName);
}
}