aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Touch/Controls/TouchListBox.cs
blob: 4fa50b7e62a1f185bb1f2db599a9a6e620df13fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
generated by cgit v1.3.1 (git 2.54.0) at 2026-07-23 08:45:54 +0000
 


re>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Tango.Core.Commands;
using Tango.Core.EventArguments;
using Tango.Core.ExtensionMethods;

namespace Tango.Touch.Controls
{
    [ContentProperty(nameof(ItemsSource))]
    public class TouchListBox : Control
    {
        private ItemsControl _items_control;
        private bool _isLoaded;
        private List<TouchListBoxItem> _awaitingSelectionItems;
        private TouchListBoxItem _firstMultiSelectionItem;

        static TouchListBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TouchListBox), new FrameworkPropertyMetadata(typeof(TouchListBox)));
        }

        public Object SelectedItem
        {
            get { return (Object)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }
        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(Object), typeof(TouchListBox), new PropertyMetadata(null, (d, e) => (d as TouchListBox).OnSelectedItemChanged()));

        public IList SelectedItems
        {
            get { return (IList)GetValue(SelectedItemsProperty); }
            set { SetValue(SelectedItemsProperty, value); }
        }
        public static readonly DependencyProperty SelectedItemsProperty =
            DependencyProperty.Register("SelectedItems", typeof(IList), typeof(TouchListBox), new PropertyMetadata(null));

        public IList ItemsSource
        {
            get { return (IList)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }
        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IList), typeof(TouchListBox), new PropertyMetadata(null, (d, e) => (d as TouchListBox).OnItemsSourceChanged()));

        public DataTemplate ItemTemplate
        {
            get { return (DataTemplate)GetValue(ItemTemplateProperty); }
            set { SetValue(ItemTemplateProperty, value); }
        }
        public static readonly DependencyProperty ItemTemplateProperty =
            DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(TouchListBox), new PropertyMetadata(null));

        public Style ItemContainerStyle
        {
            get { return (Style)GetValue(ItemContainerStyleProperty); }
            set { SetValue(ItemContainerStyleProperty, value); }
        }
        public static readonly DependencyProperty ItemContainerStyleProperty =
            DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(TouchListBox), new PropertyMetadata(null));

        public SelectionMode SelectionMode
        {
            get { return (SelectionMode)GetValue(SelectionModeProperty); }
            set { SetValue(SelectionModeProperty, value); }
        }
        public static readonly DependencyProperty SelectionModeProperty =
            DependencyProperty.Register("SelectionMode", typeof(SelectionMode), typeof(TouchListBox), new PropertyMetadata(SelectionMode.Single));

        public bool IsMultiSelecting
        {
            get { return (bool)GetValue(IsMultiSelectingProperty); }
            set { SetValue(IsMultiSelectingProperty, value); }
        }
        public static readonly DependencyProperty IsMultiSelectingProperty =
            DependencyProperty.Register("IsMultiSelecting", typeof(bool), typeof(TouchListBox), new PropertyMetadata(false));

        public LightTouchScrollViewer ScrollViewer
        {
            get { return (LightTouchScrollViewer)GetValue(ScrollViewerProperty); }
            set { SetValue(ScrollViewerProperty, value); }
        }
        public static readonly DependencyProperty ScrollViewerProperty =
            DependencyProperty.Register("ScrollViewer", typeof(LightTouchScrollViewer), typeof(TouchListBox), new PropertyMetadata(null));

        public ICommand ItemSelectedCommand
        {
            get { return (ICommand)GetValue(ItemSelectedCommandProperty); }
            set { SetValue(ItemSelectedCommandProperty, value); }
        }
        public static readonly DependencyProperty ItemSelectedCommandProperty =
            DependencyProperty.Register("ItemSelectedCommand", typeof(ICommand), typeof(TouchListBox), new PropertyMetadata(null));

        public RelayCommand<TouchListBoxItem> ListBoxItemLoadedCommand
        {
            get { return (RelayCommand<TouchListBoxItem>)GetValue(ListBoxItemLoadedCommandProperty); }
            set { SetValue(ListBoxItemLoadedCommandProperty, value); }
        }
        public static readonly DependencyProperty ListBoxItemLoadedCommandProperty =
            DependencyProperty.Register("ListBoxItemLoadedCommand", typeof(RelayCommand<TouchListBoxItem>), typeof(TouchListBox), new PropertyMetadata(null));

        public bool DisableScrolling
        {
            get { return (bool)GetValue(DisableScrollingProperty); }
            set { SetValue(DisableScrollingProperty, value); }
        }
        public static readonly DependencyProperty DisableScrollingProperty =
            DependencyProperty.Register("DisableScrolling", typeof(bool), typeof(TouchListBox), new PropertyMetadata(false));

        public bool DisableRipple
        {
            get { return (bool)GetValue(DisableRippleProperty); }
            set { SetValue(DisableRippleProperty, value); }
        }
        public static readonly DependencyProperty DisableRippleProperty =
            DependencyProperty.Register("DisableRipple", typeof(bool), typeof(TouchListBox), new PropertyMetadata(false));

        public Visibility ScrollBarVisibility
        {
            get { return (Visibility)GetValue(ScrollBarVisibilityProperty); }
            set { SetValue(ScrollBarVisibilityProperty, value); }
        }
        public static readonly DependencyProperty ScrollBarVisibilityProperty =
            DependencyProperty.Register("ScrollBarVisibility", typeof(Visibility), typeof(TouchListBox), new PropertyMetadata(Visibility.Visible));

        public String ValuePath
        {
            get { return (String)GetValue(ValuePathProperty); }
            set { SetValue(ValuePathProperty, value); }
        }
        public static readonly DependencyProperty ValuePathProperty =
            DependencyProperty.Register("ValuePath", typeof(String), typeof(TouchListBox), new PropertyMetadata(null));



        public TouchListBox()
        {
            _awaitingSelectionItems = new List<TouchListBoxItem>();
            Loaded += TouchListBox_Loaded;

            ListBoxItemLoadedCommand = new RelayCommand<TouchListBoxItem>(RegisterListBoxItemEvents);
        }

        private void RegisterListBoxItemEvents(TouchListBoxItem item)
        {
            if (item.Tag == null)
            {
                item.Tag = 1;
                item.RegisterForPreviewMouseOrTouchDown(OnItemMouseDown);
                item.RegisterForPreviewMouseOrTouchUp(OnItemMouseUp);
            }
        }

        private void TouchListBox_Loaded(object sender, RoutedEventArgs e)
        {
            if (!_isLoaded)
            {
                var stack = _items_control.FindChild<StackPanel>();

                if (stack != null)
                {
                    _items_control.Bind(ItemsControl.HeightProperty, stack, StackPanel.ActualHeightProperty, BindingMode.OneWay);
                    _isLoaded = true;
                    RegisterItemsEvents();
                    OnSelectedItemChanged();
                }
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _items_control = GetTemplateChild("PART_ItemsControl") as ItemsControl;
            ScrollViewer = GetTemplateChild("PART_ScrollViewer") as LightTouchScrollViewer;

            _items_control.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;

            OnSelectedItemChanged();
        }

        private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
        {
            if (_items_control.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            {
                try
                {
                    _items_control.UpdateLayout();
                }
                catch { }

                RegisterItemsEvents();
                OnSelectedItemChanged();
            }
        }

        private void UpdateSelectedItems()
        {
            var selectedItem = GetItems().FirstOrDefault(x => x.IsSelected);
            if (selectedItem != null)
            {
                SelectedItem = selectedItem.DataContext;
            }

            if (SelectedItems != null)
            {
                SelectedItems.Clear();

                foreach (var item in GetItems().Where(x => x.IsSelected))
                {
                    SelectedItems.Add(item.DataContext);
                }
            }
        }

        public List<TouchListBoxItem> GetItems()
        {
            return _items_control.FindVisualChildren<TouchListBoxItem>().ToList();
        }

        private void RegisterItemsEvents()
        {
            var items = GetItems();

            foreach (var item in items)
            {
                if (item.Tag == null)
                {
                    item.Tag = 1;
                    item.RegisterForPreviewMouseOrTouchDown(OnItemMouseDown);
                    item.RegisterForPreviewMouseOrTouchUp(OnItemMouseUp);
                }
            }
        }

        private async void OnItemMouseDown(object sender, MouseOrTouchEventArgs e)
        {
            var item = (e.Source is TouchListBoxItem) ? e.Source as TouchListBoxItem : (e.Source as DependencyObject).FindAncestor<TouchListBoxItem>();
            var otherItems = GetItems().Where(x => x != item).ToList();

            if (SelectionMode == SelectionMode.Multiple)
            {
                if (!IsMultiSelecting)
                {
                    _awaitingSelectionItems.Add(item);
                    await Task.Delay(500);

                    if (_awaitingSelectionItems.Contains(item))
                    {
                        _awaitingSelectionItems.Remove(item);

                        if (ScrollViewer.IsMouseTouchDown && !ScrollViewer.IsScrolling)
                        {
                            _firstMultiSelectionItem = item;
                            otherItems.ForEach(x => x.IsSelected = false);
                            item.IsSelected = true;
                            IsMultiSelecting = true;

                            UpdateSelectedItems();
                        }
                    }
                }
            }
        }

        private void OnItemMouseUp(object sender, MouseOrTouchEventArgs e)
        {
            if (ScrollViewer.IsAfterScrolling) return;

            var item = (e.Source is TouchListBoxItem) ? e.Source as TouchListBoxItem : (e.Source as DependencyObject).FindAncestor<TouchListBoxItem>();
            var otherItems = GetItems().Where(x => x != item).ToList();

            if (!IsMultiSelecting)
            {
                _awaitingSelectionItems.Remove(item);

                if (SelectionMode != SelectionMode.Multiple)
                {
                    otherItems.ForEach(x => x.IsSelected = false);
                    item.IsSelected = true;
                    ItemSelectedCommand?.Execute(item.DataContext);
                }
                else
                {
                    SelectedItem = item.DataContext;
                    ItemSelectedCommand?.Execute(item.DataContext);
                }
            }
            else if (SelectionMode == SelectionMode.Multiple && IsMultiSelecting)
            {
                if (!ScrollViewer.IsScrolling)
                {
                    if (item != _firstMultiSelectionItem)
                    {
                        item.IsSelected = !item.IsSelected;
                    }

                    _firstMultiSelectionItem = null;

                    if (!item.IsSelected && otherItems.All(x => !x.IsSelected))
                    {
                        IsMultiSelecting = false;
                    }
                }
            }

            UpdateSelectedItems();
        }

        private void OnSelectedItemChanged()
        {
            var items = GetItems();
            items.ForEach(x => x.IsSelected = false);

            TouchListBoxItem item = null;

            if (String.IsNullOrWhiteSpace(ValuePath) || SelectedItem == null)
            {
                item = items.FirstOrDefault(x => x.DataContext.Equals(SelectedItem));
            }
            else
            {
                item = items.FirstOrDefault(x => x.DataContext.GetPropertyValueByPath(ValuePath).Equals(SelectedItem.GetPropertyValueByPath(ValuePath)));
            }

            if (item != null)
            {
                item.IsSelected = true;
                UpdateSelectedItems();
            }
        }

        private void OnItemsSourceChanged()
        {
            if (ScrollViewer != null)
            {
                ScrollViewer.ScrollToTop();
            }
        }

        public void ScrollToItem(Object item)
        {
            var ee = ScrollViewer.FindVisualChildren<FrameworkElement>();
            var element = ScrollViewer.FindVisualChildren<FrameworkElement>().FirstOrDefault(x => x.DataContext == item);
            ScrollViewer.ScrollToElement(element);
        }

        
    }
}