366 lines
13 KiB
C#
366 lines
13 KiB
C#
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
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.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Navigation;
|
|
using System.Windows.Shapes;
|
|
using Xceed.Wpf.Toolkit.Primitives;
|
|
|
|
namespace CtrEditor.ObjetosSim.UserControls
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for TreeListControlOS.xaml
|
|
/// </summary>
|
|
public partial class TreeListControlOS : UserControl
|
|
{
|
|
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
|
|
nameof(ItemsSource), typeof(ObservableCollection<osBase>), typeof(TreeListControlOS), new PropertyMetadata(null, OnItemsSourceChanged));
|
|
|
|
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
|
|
nameof(SelectedItem), typeof(TreeItemViewModel), typeof(TreeListControlOS), new PropertyMetadata(null, OnSelectedItemChanged));
|
|
|
|
|
|
public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
|
|
|
|
public ObservableCollection<osBase> ItemsSource
|
|
{
|
|
get => (ObservableCollection<osBase>)GetValue(ItemsSourceProperty);
|
|
set => SetValue(ItemsSourceProperty, value);
|
|
}
|
|
|
|
public TreeItemViewModel SelectedItem
|
|
{
|
|
get => (TreeItemViewModel)GetValue(SelectedItemProperty);
|
|
set => SetValue(SelectedItemProperty, value);
|
|
}
|
|
|
|
public ObservableCollection<TreeItemViewModel> Items { get; set; } = new ObservableCollection<TreeItemViewModel>();
|
|
|
|
public TreeListControlOS()
|
|
{
|
|
InitializeComponent();
|
|
DataContext = this;
|
|
}
|
|
|
|
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (d is TreeListControlOS control)
|
|
{
|
|
control.LoadItems((ObservableCollection<osBase>)e.NewValue);
|
|
}
|
|
}
|
|
|
|
private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (d is TreeListControlOS control && e.NewValue is TreeItemViewModel newItem)
|
|
{
|
|
// Update the TreeView selection if necessary
|
|
control.UpdateTreeViewSelection(newItem);
|
|
control.OnSelectionChanged(new SelectionChangedEventArgs(newItem));
|
|
}
|
|
}
|
|
|
|
private void UpdateTreeViewSelection(TreeItemViewModel selectedItem)
|
|
{
|
|
if (treeView != null && selectedItem != null)
|
|
{
|
|
TreeViewSelectedItemExBehavior.SetSelectedItemEx(treeView, selectedItem);
|
|
}
|
|
}
|
|
|
|
|
|
public TreeItemViewModel FindViewModelForItem(osBase item)
|
|
{
|
|
foreach (var i in Items)
|
|
{
|
|
if (i.Item == item)
|
|
return i;
|
|
foreach (var child in i.Children)
|
|
if (child.Item == item)
|
|
return child;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
|
{
|
|
if (e.NewValue is TreeItemViewModel selectedItem)
|
|
{
|
|
SelectedItem = selectedItem;
|
|
OnSelectionChanged(new SelectionChangedEventArgs(selectedItem));
|
|
}
|
|
}
|
|
|
|
private void OnSelectionChanged(SelectionChangedEventArgs e)
|
|
{
|
|
SelectionChanged?.Invoke(this, e);
|
|
}
|
|
|
|
private void LoadItems(ObservableCollection<osBase> allItems)
|
|
{
|
|
Items.Clear();
|
|
if (allItems == null) return;
|
|
|
|
var rootItems = allItems.Where(i => !i.Cloned);
|
|
foreach (var item in rootItems)
|
|
{
|
|
Items.Add(new TreeItemViewModel(item, allItems));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public partial class vmTreeListControlOS : ObservableObject
|
|
{
|
|
[ObservableProperty]
|
|
private object selectedItemTreeViewSs = new object();
|
|
|
|
[ObservableProperty]
|
|
private ObservableCollection<object> selectedItemsTreeViewSs = new ObservableCollection<object>();
|
|
|
|
[ObservableProperty]
|
|
private ObservableCollection<TreeItemViewModel> itemsTreeViewSs = new ObservableCollection<TreeItemViewModel>();
|
|
|
|
}
|
|
|
|
|
|
public class TreeItemViewModel
|
|
{
|
|
public osBase Item { get; set; }
|
|
public ObservableCollection<TreeItemViewModel> Children { get; set; } = new ObservableCollection<TreeItemViewModel>();
|
|
|
|
public TreeItemViewModel(osBase item, ObservableCollection<osBase> allItems)
|
|
{
|
|
Item = item;
|
|
LoadChildren(allItems);
|
|
}
|
|
|
|
private void LoadChildren(ObservableCollection<osBase> allItems)
|
|
{
|
|
foreach (var child in allItems.Where(i => i.Cloned && i.Cloned_from == Item.Id))
|
|
{
|
|
Children.Add(new TreeItemViewModel(child, allItems));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cambia la clase SelectionChangedEventArgs
|
|
public class SelectionChangedEventArgs : EventArgs
|
|
{
|
|
public TreeItemViewModel SelectedItem { get; }
|
|
|
|
public SelectionChangedEventArgs(TreeItemViewModel selectedItem)
|
|
{
|
|
SelectedItem = selectedItem;
|
|
}
|
|
}
|
|
|
|
|
|
public static class TreeViewSelectedItemExBehavior
|
|
{
|
|
private static List<TreeView> isRegisteredToSelectionChanged = new List<TreeView>();
|
|
|
|
public static readonly DependencyProperty SelectedItemExProperty =
|
|
DependencyProperty.RegisterAttached("SelectedItemEx",
|
|
typeof(object),
|
|
typeof(TreeViewSelectedItemExBehavior),
|
|
new FrameworkPropertyMetadata(new object(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemExChanged, null));
|
|
|
|
#region SelectedItemEx
|
|
|
|
public static object GetSelectedItemEx(TreeView target)
|
|
{
|
|
return target.GetValue(SelectedItemExProperty);
|
|
}
|
|
|
|
public static void SetSelectedItemEx(TreeView target, object value)
|
|
{
|
|
target.SetValue(SelectedItemExProperty, value);
|
|
var treeViewItemToSelect = GetTreeViewItem(target, value);
|
|
if (treeViewItemToSelect == null)
|
|
{
|
|
if (target.SelectedItem == null)
|
|
return;
|
|
var treeViewItemToUnSelect = GetTreeViewItem(target, target.SelectedItem);
|
|
treeViewItemToUnSelect.IsSelected = false;
|
|
}
|
|
else
|
|
treeViewItemToSelect.IsSelected = true;
|
|
}
|
|
|
|
public static void OnSelectedItemExChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
var treeView = depObj as TreeView;
|
|
if (treeView == null)
|
|
return;
|
|
if (!isRegisteredToSelectionChanged.Contains(treeView))
|
|
{
|
|
treeView.SelectedItemChanged += TreeView_SelectedItemChanged;
|
|
isRegisteredToSelectionChanged.Add(treeView);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
private static void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
|
{
|
|
var treeView = (TreeView)sender;
|
|
SetSelectedItemEx(treeView, e.NewValue);
|
|
}
|
|
|
|
#region Helper Structures & Methods
|
|
|
|
public class MyVirtualizingStackPanel : VirtualizingStackPanel
|
|
{
|
|
/// <summary>
|
|
/// Publically expose BringIndexIntoView.
|
|
/// </summary>
|
|
public void BringIntoView(int index)
|
|
{
|
|
BringIndexIntoView(index);
|
|
}
|
|
}
|
|
|
|
/// <summary>Recursively search for an item in this subtree.</summary>
|
|
/// <param name="container">The parent ItemsControl. This can be a TreeView or a TreeViewItem.</param>
|
|
/// <param name="item">The item to search for.</param>
|
|
/// <returns>The TreeViewItem that contains the specified item.</returns>
|
|
private static TreeViewItem GetTreeViewItem(ItemsControl container, object item)
|
|
{
|
|
if (container != null)
|
|
{
|
|
if (container.DataContext == item)
|
|
{
|
|
return container as TreeViewItem;
|
|
}
|
|
|
|
// Expand the current container
|
|
if (container is TreeViewItem && !((TreeViewItem)container).IsExpanded)
|
|
{
|
|
container.SetValue(TreeViewItem.IsExpandedProperty, true);
|
|
}
|
|
|
|
// Try to generate the ItemsPresenter and the ItemsPanel.
|
|
// by calling ApplyTemplate. Note that in the
|
|
// virtualizing case even if the item is marked
|
|
// expanded we still need to do this step in order to
|
|
// regenerate the visuals because they may have been virtualized away.
|
|
|
|
container.ApplyTemplate();
|
|
ItemsPresenter itemsPresenter =
|
|
(ItemsPresenter)container.Template.FindName("ItemsHost", container);
|
|
if (itemsPresenter != null)
|
|
{
|
|
itemsPresenter.ApplyTemplate();
|
|
}
|
|
else
|
|
{
|
|
// The Tree template has not named the ItemsPresenter,
|
|
// so walk the descendents and find the child.
|
|
itemsPresenter = FindVisualChild<ItemsPresenter>(container);
|
|
if (itemsPresenter == null)
|
|
{
|
|
container.UpdateLayout();
|
|
|
|
itemsPresenter = FindVisualChild<ItemsPresenter>(container);
|
|
}
|
|
}
|
|
|
|
Panel itemsHostPanel = (Panel)VisualTreeHelper.GetChild(itemsPresenter, 0);
|
|
|
|
|
|
// Ensure that the generator for this panel has been created.
|
|
UIElementCollection children = itemsHostPanel.Children;
|
|
|
|
MyVirtualizingStackPanel virtualizingPanel =
|
|
itemsHostPanel as MyVirtualizingStackPanel;
|
|
|
|
for (int i = 0, count = container.Items.Count; i < count; i++)
|
|
{
|
|
TreeViewItem subContainer;
|
|
if (virtualizingPanel != null)
|
|
{
|
|
// Bring the item into view so
|
|
// that the container will be generated.
|
|
virtualizingPanel.BringIntoView(i);
|
|
|
|
subContainer =
|
|
(TreeViewItem)container.ItemContainerGenerator.
|
|
ContainerFromIndex(i);
|
|
}
|
|
else
|
|
{
|
|
subContainer =
|
|
(TreeViewItem)container.ItemContainerGenerator.
|
|
ContainerFromIndex(i);
|
|
|
|
// Bring the item into view to maintain the
|
|
// same behavior as with a virtualizing panel.
|
|
subContainer.BringIntoView();
|
|
}
|
|
|
|
if (subContainer != null)
|
|
{
|
|
// Search the next level for the object.
|
|
TreeViewItem resultContainer = GetTreeViewItem(subContainer, item);
|
|
if (resultContainer != null)
|
|
{
|
|
return resultContainer;
|
|
}
|
|
else
|
|
{
|
|
// The object is not under this TreeViewItem
|
|
// so collapse it.
|
|
subContainer.IsExpanded = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>Search for an element of a certain type in the visual tree.</summary>
|
|
/// <typeparam name="T">The type of element to find.</typeparam>
|
|
/// <param name="visual">The parent element.</param>
|
|
/// <returns></returns>
|
|
private static T FindVisualChild<T>(Visual visual) where T : Visual
|
|
{
|
|
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
|
|
{
|
|
Visual child = (Visual)VisualTreeHelper.GetChild(visual, i);
|
|
if (child != null)
|
|
{
|
|
T correctlyTyped = child as T;
|
|
if (correctlyTyped != null)
|
|
{
|
|
return correctlyTyped;
|
|
}
|
|
|
|
T descendent = FindVisualChild<T>(child);
|
|
if (descendent != null)
|
|
{
|
|
return descendent;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
}
|