xmake.repo/packages/n/noesis/latest/Include/NsGui/ItemsControl.h
2024-12-22 19:15:02 +08:00

352 lines
13 KiB
C++

////////////////////////////////////////////////////////////////////////////////////////////////////
// NoesisGUI - http://www.noesisengine.com
// Copyright (c) 2013 Noesis Technologies S.L. All Rights Reserved.
////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __GUI_ITEMSCONTROL_H__
#define __GUI_ITEMSCONTROL_H__
#include <NsCore/Noesis.h>
#include <NsGui/CoreApi.h>
#include <NsGui/Control.h>
namespace Noesis
{
class DataTemplateSelector;
class DataTemplate;
class ItemContainerGenerator;
class ItemsPanelTemplate;
class ItemCollection;
class ItemsPresenter;
class Panel;
class ItemsControlTest;
struct NotifyCollectionChangedEventArgs;
NS_WARNING_PUSH
NS_MSVC_WARNING_DISABLE(4251 4275)
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Represents a control that can be used to present a collection of items.
///
/// .. code-block:: xml
/// :caption: XAML
///
/// <ItemsControl>
/// <ItemsControl.ItemTemplate>
/// <DataTemplate>
/// <Grid Margin="0,0,0,5">
/// <Grid.ColumnDefinitions>
/// <ColumnDefinition Width="*"/>
/// <ColumnDefinition Width="100"/>
/// </Grid.ColumnDefinitions>
/// <TextBlock Text="{Binding Title}"/>
/// <ProgressBar Grid.Column="1" Minimum="0" Maximum="100" Value="{Binding Completion}"/>
/// </Grid>
/// </DataTemplate>
/// </ItemsControl.ItemTemplate>
/// </ItemsControl>
///
/// Each ItemsControl type has a corresponding item container type. The corresponding item container
/// for each ItemsControl appends Item to its name. For example, for ListBox, the item containers
/// are ListBoxItem controls; for ComboBox, they are ComboBoxItem controls. You can explicitly
/// create a container type for each item in the ItemsControl, but it is not necessary. When you do
/// not explicitly create the container type, one is generated that contains a data item in the item
/// collection. For example, if you bind a collection of string objects to the ItemsSource property
/// of a ListBox, you do not explicitly create ListBoxItem objects, but the ListBox will generate
/// one for each string. You can access a generated item container by using the
/// ItemContainerGenerator property
///
/// http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.aspx
////////////////////////////////////////////////////////////////////////////////////////////////////
class NS_GUI_CORE_API ItemsControl: public Control
{
public:
ItemsControl();
~ItemsControl();
/// Gets or sets a value that controls the range of values assigned to the AlternationIndex
/// property attached to each generated container.
/// * The default value 0 means "do not set AlternationIndex"
/// * A positive value means "assign AlternationIndex in the range [0, AlternationCount) so
/// that adjacent containers receive different values"
//@{
int GetAlternationCount() const;
void SetAlternationCount(int value);
//@}
/// Gets the index set on generated containers, when the ItemsControl's AlternationCount
/// property is positive. The AlternationIndex lies in the range [0, AlternationCount), and
/// adjacent containers always get assigned different values
static int GetAlternationIndex(const DependencyObject* element);
/// Gets or sets a path to a value on the source object to serve as the visual representation
/// of the object
//@{
const char* GetDisplayMemberPath() const;
void SetDisplayMemberPath(const char* path);
//@}
/// Gets a value that indicates whether the ItemsControl contains items
bool GetHasItems() const;
/// Gets the ItemContainerGenerator associated with this control
ItemContainerGenerator* GetItemContainerGenerator() const;
/// Gets or sets the Style that is applied to the container element generated for each item.
//@{
Style* GetItemContainerStyle() const;
void SetItemContainerStyle(Style* style);
//@}
/// Gets or sets the ItemsPanelTemplate that defines the Panel that controls the layout of items
//@{
ItemsPanelTemplate* GetItemsPanel() const;
void SetItemsPanel(ItemsPanelTemplate* value);
//@}
/// Returns a new instance of the default items panel for this ItemsControl
virtual Ptr<Panel> GetDefaultItemsPanel() const;
/// Gets or sets a collection used to generate the content of the ItemsControl. When the
/// ItemsSource property is set, the Items collection is made read-only and fixed-size
//@{
BaseComponent* GetItemsSource() const;
void SetItemsSource(BaseComponent* items);
//@}
/// Gets or sets the DataTemplate used to display each item.
//@{
DataTemplate* GetItemTemplate() const;
void SetItemTemplate(DataTemplate* value);
//@}
/// Gets or sets a DataTemplateSelector that provides custom logic for choosing the template
/// used to display the header
//@{
DataTemplateSelector* GetItemTemplateSelector() const;
void SetItemTemplateSelector(DataTemplateSelector* selector);
//@}
/// Gets the collection used to generate the content of the ItemsControl. When the ItemsSource
/// property is set, the Items collection is made read-only and fixed-size
ItemCollection* GetItems() const;
/// Returns the ItemsControl that owns the specified container element.
static ItemsControl* ItemsControlFromItemContainer(DependencyObject* container);
/// Returns the container that owns the given element. If *itemsControl* is not null, returns a
/// container that belongs to the given ItemsControl. If *itemsControl* is null, returns the
/// closest container belonging to any ItemsControl. Returns null if no such container exists
static DependencyObject* ContainerFromElement(ItemsControl* itemsControl,
DependencyObject* element);
/// Returns the container belonging to the current ItemsControl that owns the given container
/// element. Returns null if no such container exists
DependencyObject* ContainerFromElement(DependencyObject* element);
/// Returns the ItemsControl that the specified element hosts items for. If IsItemsHost is set
/// to true on element in a style or if element is a panel created by the ItemsPresenter for an
/// ItemsControl, the ItemsControl is returned; otherwise, a null reference
static ItemsControl* GetItemsOwner(DependencyObject* itemsHost);
/// Determines if the specified item is (or is eligible to be) its own container
bool IsItemItsOwnContainer(BaseComponent* item) const;
public:
/// Dependency properties
//@{
static const DependencyProperty* AlternationCountProperty;
static const DependencyProperty* AlternationIndexProperty; // attached property
static const DependencyProperty* DisplayMemberPathProperty;
static const DependencyProperty* HasItemsProperty;
static const DependencyProperty* ItemContainerStyleProperty;
static const DependencyProperty* ItemsPanelProperty;
static const DependencyProperty* ItemsSourceProperty;
static const DependencyProperty* ItemTemplateProperty;
static const DependencyProperty* ItemTemplateSelectorProperty;
//@}
protected:
// Updates items presenter and items host
void RefreshItems();
// Gets the panel which is marked by the template to visually host the items
Panel* GetItemsHost() const;
// Creates or identifies the element that is used to display the given item.
virtual Ptr<DependencyObject> GetContainerForItemOverride() const;
// Determines if the specified item is (or is eligible to be) its own container.
virtual bool IsItemItsOwnContainerOverride(BaseComponent* item) const;
// Configures container
virtual void PrepareContainerForItemOverride(DependencyObject* container,
BaseComponent* item) const;
// Clears container attachments
virtual void ClearContainerForItemOverride(DependencyObject* container,
BaseComponent* item) const;
// Applies the appropriate style to item container
virtual void ApplyItemContainerStyle(DependencyObject* container) const;
static void OverrideContainerStyle(DependencyObject* container, const char* key);
// Invoked when the Items property changes
virtual void OnItemsChanged(const NotifyCollectionChangedEventArgs& args);
/// Invoked when the current item changes
virtual void OnCurrentItemChanged();
// Invoked when item containers are generated/destroyed for this ItemsControl
virtual void OnContainersGenerated();
// Invoked when Item template changes
virtual void OnItemTemplateChanged(DataTemplate* oldTemplate, DataTemplate* newTemplate);
// Invoked when Item template selector changes
virtual void OnItemTemplateSelectorChanged(DataTemplateSelector* oldSelector,
DataTemplateSelector* newSelector);
// Tries to bring item into view
void OnBringItemIntoView(BaseComponent* item);
// Finds next available container for navigation in the specified direction
DependencyObject* NextContainer(int startIndex, int direction, bool allowCycle);
// Gets the number of items visible in the viewport. Returns 0 when no viewport is available.
//@{
int GetVerticalPageSize() const;
int GetHorizontalPageSize() const;
//@}
// From DependencyObject
//@{
void OnInit() override;
bool OnPropertyChanged(const DependencyPropertyChangedEventArgs& args) override;
//@}
// From UIElement
//@{
void OnKeyDown(const KeyEventArgs& e) override;
//@}
// From FrameworkElement
//@{
void CloneOverride(FrameworkElement* clone, FrameworkTemplate* template_) const override;
uint32_t GetLogicalChildrenCount() const override;
Ptr<BaseComponent> GetLogicalChild(uint32_t index) const override;
void OnTemplateChanged(FrameworkTemplate* oldTemplate, FrameworkElement* oldRoot,
FrameworkTemplate* newTemplate, FrameworkElement* newRoot) override;
Size MeasureOverride(const Size& availableSize) override;
//@}
// Called when ItemsSource has changed
virtual void OnItemsSourceChanged(BaseComponent* oldSource,
BaseComponent* newSource);
// ItemsControl flag management
//@{
void SetItemsFlag(uint32_t flag);
void ClearItemsFlag(uint32_t flag);
bool CheckItemsFlag(uint32_t flag) const;
struct ScopeItemsFlag
{
ScopeItemsFlag(ItemsControl* ic, uint32_t f);
~ScopeItemsFlag();
private:
ItemsControl* itemsControl;
uint32_t flag;
};
enum
{
UsesExternalCollectionView = 1,
RemovingExternalCollectionView = UsesExternalCollectionView * 2,
NeedsRefreshItems = RemovingExternalCollectionView * 2,
ItemsHaveChanged = NeedsRefreshItems * 2,
ContainersWereGenerated = ItemsHaveChanged * 2,
LastFlag = ContainersWereGenerated
};
//@}
void PrepareContainer(BaseComponent* item, ItemsControl* parent);
private:
friend class ItemContainerGenerator;
friend class ItemCollection;
friend class ItemsPresenter;
friend class Panel;
friend class VirtualizingPanel;
friend class ItemsControlTest;
// ItemContainerGenerator host interface
//@{
Ptr<DependencyObject> GetContainerForItem(BaseComponent* item) const;
void PrepareItemContainer(DependencyObject* container, BaseComponent* item) const;
void ClearContainerForItem(DependencyObject* container, BaseComponent* item) const;
bool IsHostForItemContainer(DependencyObject* container) const;
//@}
static bool IsContainerForItemsControl(DependencyObject* element,
ItemsControl* itemsControl);
void OnCollectionViewSourceChanged(BaseComponent* sender,
const DependencyPropertyChangedEventArgs& args);
void OnItemsChangedStart(BaseComponent* sender,
const NotifyCollectionChangedEventArgs& args);
void OnItemsChangedEnd(BaseComponent* sender,
const NotifyCollectionChangedEventArgs& args);
void OnCurrentItemChangedInternal(BaseComponent* c, const EventArgs& args);
void OnGeneratorChanged(BaseComponent* sender, const EventArgs& e);
// Allows ItemsPresenter to update items presenter
void SetItemsPresenter(ItemsPresenter* itemsPresenter);
// Allows Panel to update items host
void SetItemsHost(Panel* itemsHost);
Orientation GetItemsHostOrientation() const;
bool FocusNext(int next, bool allowCycle, FocusNavigationDirection direction);
bool FocusNext(int next, bool allowCycle);
bool FocusContainer(DependencyObject* container, int next);
void EnsureItems();
void ConnectItems();
void DisconnectItems();
void InvalidateItemsPresenter();
void InvalidateItems();
bool CheckTemplateProperties();
static void SetAlternationIndex(DependencyObject* element, int value);
static void ClearAlternationIndex(DependencyObject* element);
virtual void OnAlternationCountChanged(int oldValue, int newValue);
private:
Ptr<ItemCollection> mItems;
Ptr<ItemContainerGenerator> mGenerator;
Ptr<ItemsPresenter> mItemsPresenter;
Ptr<Panel> mItemsHost;
Ptr<DataTemplate> mDisplayMemberTemplate;
uint32_t mItemsFlags;
NS_DECLARE_REFLECTION(ItemsControl, Control)
};
NS_WARNING_POP
}
#endif