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 { /// /// Interaction logic for TreeListControlOS.xaml /// public partial class TreeListControlOS : UserControl { public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( nameof(ItemsSource), typeof(ObservableCollection), 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 SelectionChanged; public ObservableCollection ItemsSource { get => (ObservableCollection)GetValue(ItemsSourceProperty); set => SetValue(ItemsSourceProperty, value); } public TreeItemViewModel SelectedItem { get => (TreeItemViewModel)GetValue(SelectedItemProperty); set => SetValue(SelectedItemProperty, value); } public ObservableCollection Items { get; set; } = new ObservableCollection(); public TreeListControlOS() { InitializeComponent(); DataContext = this; } private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is TreeListControlOS control) { control.LoadItems((ObservableCollection)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 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 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 selectedItemsTreeViewSs = new ObservableCollection(); [ObservableProperty] private ObservableCollection itemsTreeViewSs = new ObservableCollection(); } public class TreeItemViewModel { public osBase Item { get; set; } public ObservableCollection Children { get; set; } = new ObservableCollection(); public TreeItemViewModel(osBase item, ObservableCollection allItems) { Item = item; LoadChildren(allItems); } private void LoadChildren(ObservableCollection 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 isRegisteredToSelectionChanged = new List(); 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 e) { var treeView = (TreeView)sender; SetSelectedItemEx(treeView, e.NewValue); } #region Helper Structures & Methods public class MyVirtualizingStackPanel : VirtualizingStackPanel { /// /// Publically expose BringIndexIntoView. /// public void BringIntoView(int index) { BringIndexIntoView(index); } } /// Recursively search for an item in this subtree. /// The parent ItemsControl. This can be a TreeView or a TreeViewItem. /// The item to search for. /// The TreeViewItem that contains the specified item. 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(container); if (itemsPresenter == null) { container.UpdateLayout(); itemsPresenter = FindVisualChild(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; } /// Search for an element of a certain type in the visual tree. /// The type of element to find. /// The parent element. /// private static T FindVisualChild(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(child); if (descendent != null) { return descendent; } } } return null; } #endregion } }