【Avalonia学习笔记】2:用ListBox代替ItemsControl作为图形VM容器

使用ItemsControl作为容器

想要在面板上显示图形,先把图形的VM都创建好,希望能传所有VM到一个列表(ObservableCollection泛型容器)里,然后界面上就能显示出对应的图形。

这些图形VM都继承自ViewModelBase,同时有一些是结点, 有一些是连线。结点是直接继承了NetworkItem_VM,然后再间接继承ViewModelBase的。

如果直接用ItemsControl作为VM容器,即:

<ItemsControl Items="{Binding UserControlVMs}" Height="1000" Width="2000"/>

设置Style和数据模板:

<UserControl.Styles>
    
    <Style Selector="ItemsControl">
      
      
        
          
            
            
              
              
                
                  {Binding xxx}"/>
                
              
            
          
        
      
      
      
        
          
            {Binding .}"/>
          
        
      
    Style>
    
    <Style Selector="ItemsControl > ContentPresenter">
      <Setter Property="Canvas.Left" Value="{Binding X}"/>
      <Setter Property="Canvas.Top" Value="{Binding Y}"/>
    Style>
  UserControl.Styles>

这种方法能实现需求,但是出来的图形会有些卡顿,仅仅在当前图形面板上操作时不太能感觉出来,但是在不同图形面板之间切换时就会有很明显的卡顿,创建12个结点,40多个控制点,然后所有这些50多个点连线在一起,切换回这个图形面板时大约需要3秒的时间(8G内存64位win10集成显卡)。

改用ListBox作为容器

在这篇问答中讨论的是WPF上的切换问题,Avalonia中也有这样的问题,然后答主意思是ListBox支持UI虚拟化,代替原生的ItemsControl效果会好一些。

改用ListBox作为VM容器:

<ListBox Name="panel" Items="{Binding UserControlVMs}" Height="1000" Width="2000"/>

设置Style和数据模板:

<UserControl.Styles>
    
    <Style Selector="ListBox#panel">
      
      
        
          
            
            
              
              
                
                  {Binding xxx"/>
                
              
            
          
        
      
      
      
        
          
            {Binding .}"/>
          
        
      
    Style>
    
    <Style Selector="ListBox#panel ListBoxItem">
      
      {Binding X}"/>
      {Binding Y}"/>
    Style>
  UserControl.Styles>

这里用ListBox#panel指明name的原因是图形里面有些也带ListBox(状态机的转移边),这里让选择器只选择这个容器ListBox。现在渲染速度比用ItemsControl快了大概三倍,和上面一样多的图形大概要用1秒的时间。

但是这种方式又带来一个问题,就是因为ListBox有指针停留和选中的问题,其中的项会产生灰色不透明和蓝色透明的背景,而且会影响下层内容的点击,问题效果和可视树如下:
【Avalonia学习笔记】2:用ListBox代替ItemsControl作为图形VM容器_第1张图片
【Avalonia学习笔记】2:用ListBox代替ItemsControl作为图形VM容器_第2张图片
如果用Enabled="False"或者IsHitTestVisible="False"确实可以解决这个问题,但是这样整个ListBox就不响应鼠标操作了,对图形的拖拽和打开右键菜单都会失效。

这里加了一个Style来解决这个问题,判断是NetWorkItem_VM的子类就设置IsHitTestVisible="True",否则就是图形连线,设置为False

<Style Selector="ListBox#panel ListBoxItem > ContentPresenter">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="IsHitTestVisible" Value="{Binding IsNetWorkItemVM}"/>
Style>

相应地,在ViewModelBase类里要加个判断的属性:

namespace sbid._VM
{
    public class ViewModelBase : ReactiveObject
    {
        // 判断这个ViewModelBase对象是不是一个NetWorkItem_VM
        // 用于在状态机中区分"线"(直线/箭头)和"元素"(状态/转移块/控制点)
        // 以将"线"设置不可点击也不会显示选中效果,防止影响到"元素"的显示和移动
        public bool IsNetWorkItemVM { get => this is NetworkItem_VM; }
    }
}

你可能感兴趣的:(#,Avalonia,Avalonia,图形建模,c#,.net,xaml)