GacUI Demo:列表的虚拟模式,不需要为每一个列表项分配内存的一种显示方法

GacUI Demo:列表的虚拟模式,不需要为每一个列表项分配内存的一种显示方法
    GacUI的所有列表控件都支持虚拟模式。虚拟模式是一种不需要为每一个列表项分配内存的一种显示方法。在开始的时候,需要高速列表一共有多少个列表项。之后,列表控件在渲染的时候,会跟数据源要求获取某一个下标所包含的数据,并且在这个数据一直处于屏幕上的时候,只会跟数据源获取一次。完整的代码可以在 http://www.gaclib.net/Demos/Controls.ListBox.VirtualMode/Demo.html看到。先上图:



    先看创建界面的代码。一般来说,所有可以随着窗口的变化自动排版的控件组织方法,都是使用一个或多个GuiTableComposition来实现的。

class  VirtualModeWindow :  public  GuiWindow
{
private :
    GuiVirtualTextList
*                     listBox;
    GuiButton
*                             buttonIncrease;
    GuiButton
*                             buttonDecrease;
    DataSource
*                             dataSource;
    
    
void  buttonIncrease_Clicked(GuiGraphicsComposition *  sender, GuiEventArgs &  arguments)
    {
        dataSource
-> SetCount(dataSource -> Count() + 100000 );
    }

    
void  buttonDecrease_Clicked(GuiGraphicsComposition *  sender, GuiEventArgs &  arguments)
    {
        dataSource
-> SetCount(dataSource -> Count() - 100000 );
    }
public :
    VirtualModeWindow()
        :GuiWindow(GetCurrentTheme()
-> CreateWindowStyle())
    {
        
this -> SetText(L " Controls.ListBox.VirtualMode " );

        GuiTableComposition
*  table = new  GuiTableComposition;
        table
-> SetRowsAndColumns( 3 2 );
        table
-> SetCellPadding( 3 );
        table
-> SetAlignmentToParent(Margin( 0 0 0 0 ));

        table
-> SetRowOption( 0 , GuiCellOption::MinSizeOption());
        table
-> SetRowOption( 1 , GuiCellOption::MinSizeOption());
        table
-> SetRowOption( 2 , GuiCellOption::PercentageOption( 1.0 ));

        table
-> SetColumnOption( 0 , GuiCellOption::PercentageOption( 1.0 ));
        table
-> SetColumnOption( 1 , GuiCellOption::MinSizeOption());

        
this -> GetContainerComposition() -> AddChild(table);
        
        {
            GuiCellComposition
*  cell = new  GuiCellComposition;
            table
-> AddChild(cell);
            cell
-> SetSite( 0 0 3 1 );

            dataSource
= new  DataSource;
            listBox
= new  GuiVirtualTextList(GetCurrentTheme() -> CreateTextListStyle(), GetCurrentTheme() -> CreateTextListItemStyle(), dataSource);
            listBox
-> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 0 0 0 ));
            listBox
-> SetHorizontalAlwaysVisible( false );
            cell
-> AddChild(listBox -> GetBoundsComposition());
        }
        {
            GuiCellComposition
*  cell = new  GuiCellComposition;
            table
-> AddChild(cell);
            cell
-> SetSite( 0 1 1 1 );

            buttonIncrease
= g::NewButton();
            buttonIncrease
-> SetText(L " Increase 100000 Items " );
            buttonIncrease
-> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 0 0 0 ));
            buttonIncrease
-> Clicked.AttachMethod( this & VirtualModeWindow::buttonIncrease_Clicked);
            cell
-> AddChild(buttonIncrease -> GetBoundsComposition());
        }
        {
            GuiCellComposition
*  cell = new  GuiCellComposition;
            table
-> AddChild(cell);
            cell
-> SetSite( 1 1 1 1 );

            buttonDecrease
= g::NewButton();
            buttonDecrease
-> SetText(L " Decrease 100000 Items " );
            buttonDecrease
-> GetBoundsComposition() -> SetAlignmentToParent(Margin( 0 0 0 0 ));
            buttonDecrease
-> Clicked.AttachMethod( this & VirtualModeWindow::buttonDecrease_Clicked);
            cell
-> AddChild(buttonDecrease -> GetBoundsComposition());
        }

        
//  set the preferred minimum client size
         this -> GetBoundsComposition() -> SetPreferredMinSize(Size( 480 480 ));
        
//  call this to calculate the size immediately if any indirect content in the table changes
        
//  so that the window can calcaulte its correct size before calling the MoveToScreenCenter()
         this -> ForceCalculateSizeImmediately();
        
//  move to the screen center
         this -> MoveToScreenCenter();
    }
};

    GuiVirtualTextList就是只有虚拟模式的GuiTextList。事实上GuiVirtualTextList是GuiTextList的基类,而GuiTextList.GetItems()返回的对象也是一个数据源。因此非虚拟模式其实也是通过虚拟模式来实现的。在数据比较少的时候,非虚拟模式操作起来十分的简单,而在数据比较多的时候,虚拟模式可以带来很好的性能。上面的代码创建了一个DataSource类来做数据源,并且有一个SetCount的函数用来更改列表里面的数量的总量,然后每一个列表项的内容都是Item xxx。这是怎么做到的呢?我们来看数据源的代码:

class  DataSource :  public  list::ItemProviderBase,  private  list::TextItemStyleProvider::ITextItemView
{
protected :
    
int                 count;
public :
    DataSource()
        :count(
100000 )
    {
    }

    
void  SetCount( int  newCount)
    {
        
if ( 0 <= newCount)
        {
            
int  oldCount = count;
            count
= newCount;
                
            
//  this->InvokeOnItemModified(affected-items-start, affected-items-count, new-items-count);
            
//  this function notifies the list control to update it's content and scroll bars
             if (oldCount < newCount)
            {
                
//  insert
                 this -> InvokeOnItemModified(oldCount,  0 , newCount - oldCount);
            }
            
else   if (oldCount > newCount)
            {
                
//  delete
                 this -> InvokeOnItemModified(newCount, oldCount - newCount,  0 );
            }
        }
    }

    
//  GuiListControl::IItemProvider

    
int  Count()
    {
        
return  count;
    }

    IDescriptable
*  RequestView( const  WString &  identifier)
    {
        
if (identifier == list::TextItemStyleProvider::ITextItemView::Identifier)
        {
            
return   this ;
        }
        
else   if (identifier == GuiListControl::IItemPrimaryTextView::Identifier)
        {
            
return   this ;
        }
        
else
        {
            
return   0 ;
        }
    }

    
void  ReleaseView(IDescriptable *  view)
    {
    }

    
//  list::TextItemStyleProvider::ITextItemView

    WString GetText(
int  itemIndex)
    {
        
return  L " Item  " + itow(itemIndex + 1 );
    }

    
bool  GetChecked( int  itemIndex)
    {
        
//  DataSource don't support check state
         return   false ;
    }

    
void  SetCheckedSilently( int  itemIndex,  bool  value)
    {
        
//  DataSource don't support check state
    }

    
//  GuiListControl::IItemPrimaryTextView

    WString GetPrimaryTextViewText(
int  itemIndex)
    {
        
return  GetText(itemIndex + 1 );
    }

    
bool  ContainsPrimaryText( int  itemIndex)
    {
        
return   true ;
    }
};

    对于GuiVirtualTextList来说,只需要实现vl::presentation::controls::list::TextItemStyleProvider::ITextItemView就可以了。GacUIIncludes.h里面已经有了using namespace vl::presentation::controls,所以在这里只需要从list::开始写。list::TextItemStyleProvider::ITextItemView还要求实现GuiListControl::IItemPrimaryTextView。在目前的GacUI里面,IItemPrimaryTextView是专门为下拉框准备的。因为下拉框允许接受任何一种列表对象当做下拉内容,所以GacUI的列表数据源默认都要求实现IItemPrimaryTextView。

    实现数据源的时候,其实并不要求数据源类继承自ITextItemView和IItemPrimaryTextView。因为GacUI都是通过RequestView来获取一个View的接口指针的,代码如上。实现这两个View也很简单,在这里就不赘述了。

    GuiTextList就介绍到这里了,接下来的几个Demo都将是关于ListView的。下一个Demo是ListView山寨Windows 7的资源管理器界面,可以在 http://www.gaclib.net/Demos/Controls.ListView.ViewSwitching/Demo.html看到。具体内容将在下一篇博客中阐述。

你可能感兴趣的:(GacUI Demo:列表的虚拟模式,不需要为每一个列表项分配内存的一种显示方法)