diff --git a/MainViewModel.cs b/MainViewModel.cs index 165d00f..36c934d 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -22,6 +22,7 @@ using ClosedXML.Excel; using DocumentFormat.OpenXml.Spreadsheet; using CommunityToolkit.Mvvm.Input; using CtrEditor.PopUps; +using CtrEditor.ObjetosSim.UserControls; namespace CtrEditor { @@ -153,11 +154,11 @@ namespace CtrEditor } [ObservableProperty] - private osBase selectedItemOsList; + private TreeItemViewModel selectedItemOsList; - partial void OnSelectedItemOsListChanged(osBase value) + partial void OnSelectedItemOsListChanged(TreeItemViewModel value) { - if (value != null) + if (value.Item != null) habilitarEliminarUserControl = true; else habilitarEliminarUserControl = false; @@ -183,6 +184,8 @@ namespace CtrEditor datosDeTrabajo = new DatosDeTrabajo(); ObjetosSimulables = new ObservableCollection(); + TypeDecorationManager.AddExpandableIListConverter(objetosSimulables.GetType()); + ListaOsBase = new ObservableCollection(); @@ -296,7 +299,7 @@ namespace CtrEditor private void DuplicarUserControl() { - if (SelectedItemOsList is osBase objDuplicar) + if (SelectedItemOsList.Item is osBase objDuplicar) DuplicarObjeto(objDuplicar, 0.5f, 0.5f); } @@ -348,7 +351,7 @@ namespace CtrEditor private void EliminarUserControl() { - if (SelectedItemOsList is osBase objEliminar) + if (SelectedItemOsList.Item is osBase objEliminar) { RemoverObjetoSimulable(objEliminar); diff --git a/MainWindow.xaml b/MainWindow.xaml index 8e33b0e..b425239 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -197,35 +197,18 @@ - - - - - - - - - - - - + + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 8337ce1..42c5aa6 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -9,6 +9,8 @@ using UserControl = System.Windows.Controls.UserControl; using CtrEditor.ObjetosSim; using System.Windows.Threading; using System.Diagnostics; +using CtrEditor.ObjetosSim.UserControls; +using DocumentFormat.OpenXml.Spreadsheet; namespace CtrEditor @@ -144,7 +146,7 @@ namespace CtrEditor var viewModel = DataContext as MainViewModel; if (viewModel != null) { - viewModel.SelectedItemOsList = datos; // Esto desencadenará ListaOs_SelectionChanged + ListaOS.SelectedItem = ListaOS.FindViewModelForItem(datos); // Esto desencadenará ListaOs_SelectionChanged } } @@ -460,15 +462,6 @@ namespace CtrEditor tt.Y = relativeY - cursorPosition.Y * st.ScaleY; } - private void TreeViewOs_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) - { - //PanelEdicion.Children.Clear(); // Limpiar el panel existente - UserControlFactory.LimpiarPropiedadesosDatos(PanelEdicion); - - if (e.NewValue != null && e.NewValue is osBase selectedObject) - CargarPropiedadesosDatos(selectedObject); - } - private void CargarPropiedadesosDatos(osBase selectedObject) { if (DataContext is MainViewModel viewModel) @@ -483,6 +476,14 @@ namespace CtrEditor } } + private void TreeListControl_SelectionChanged(object sender, ObjetosSim.UserControls.SelectionChangedEventArgs e) + { + //PanelEdicion.Children.Clear(); // Limpiar el panel existente + UserControlFactory.LimpiarPropiedadesosDatos(PanelEdicion); + + if (e.SelectedItem.Item != null && e.SelectedItem.Item is osBase selectedObject) + CargarPropiedadesosDatos(selectedObject); + } } public class FloatValidationRule : ValidationRule diff --git a/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs b/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs index bb65f0a..c97901c 100644 --- a/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs +++ b/ObjetosSim/Extraccion Datos/ucExtraccionTag.xaml.cs @@ -32,18 +32,6 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos [property: Category("Tag Extraction:")] bool extraer; - - [ObservableProperty] - [property: Description("Autocreated and cloned with Search Templates")] - [property: Category("Tag Extraction:")] - bool cloned; - - [ObservableProperty] - [property: Description("Autocreated and cloned with Search Templates")] - [property: Category("Tag Extraction:")] - [property: Hidden] - UniqueId cloned_from; - [ObservableProperty] bool new_Row; diff --git a/ObjetosSim/UserControls/TreeListControlOS.xaml b/ObjetosSim/UserControls/TreeListControlOS.xaml new file mode 100644 index 0000000..287ce80 --- /dev/null +++ b/ObjetosSim/UserControls/TreeListControlOS.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/ObjetosSim/UserControls/TreeListControlOS.xaml.cs b/ObjetosSim/UserControls/TreeListControlOS.xaml.cs new file mode 100644 index 0000000..cc36385 --- /dev/null +++ b/ObjetosSim/UserControls/TreeListControlOS.xaml.cs @@ -0,0 +1,365 @@ +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 + } + +} diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs index 4818cba..82cb27f 100644 --- a/ObjetosSim/osBase.cs +++ b/ObjetosSim/osBase.cs @@ -320,6 +320,17 @@ namespace CtrEditor.ObjetosSim } } + [ObservableProperty] + [property: Description("Autocreated and cloned with Search Templates")] + [property: Category("Tag Extraction:")] + bool cloned; + + [ObservableProperty] + [property: Description("Autocreated and cloned with Search Templates")] + [property: Category("Tag Extraction:")] + [property: Hidden] + UniqueId cloned_from; + private async void TimerCallback(object state) { diff --git a/XAMLhelpers.cs b/XAMLhelpers.cs index 7c7b9a0..c8708af 100644 --- a/XAMLhelpers.cs +++ b/XAMLhelpers.cs @@ -10,9 +10,126 @@ using Xceed.Wpf.Toolkit.PropertyGrid; using CtrEditor.ObjetosSim.Extraccion_Datos; using CtrEditor.ObjetosSim; using System.Collections.ObjectModel; +using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; +using System.Collections; namespace CtrEditor { + public class ListItemPropertyDescriptor : PropertyDescriptor + { + private readonly IList owner; + private readonly int index; + + public ListItemPropertyDescriptor(IList owner, int index) : base($"[{index}]", null) + { + this.owner = owner; + this.index = index; + + } + + public override AttributeCollection Attributes + { + get + { + var attributes = TypeDescriptor.GetAttributes(GetValue(null), false); + //If the Xceed expandable object attribute is not applied then apply it + if (!attributes.OfType().Any()) + { + attributes = AddAttribute(new ExpandableObjectAttribute(), attributes); + } + + //set the xceed order attribute + attributes = AddAttribute(new PropertyOrderAttribute(index), attributes); + + return attributes; + } + } + private AttributeCollection AddAttribute(Attribute newAttribute, AttributeCollection oldAttributes) + { + Attribute[] newAttributes = new Attribute[oldAttributes.Count + 1]; + oldAttributes.CopyTo(newAttributes, 1); + newAttributes[0] = newAttribute; + + return new AttributeCollection(newAttributes); + } + + public override bool CanResetValue(object component) + { + return false; + } + + public override object GetValue(object component) + { + return Value; + } + + private T Value + => owner[index]; + + public override void ResetValue(object component) + { + throw new NotImplementedException(); + } + + public override void SetValue(object component, object value) + { + owner[index] = (T)value; + } + + public override bool ShouldSerializeValue(object component) + { + return false; + } + + public override Type ComponentType + => owner.GetType(); + + public override bool IsReadOnly + => false; + + public override Type PropertyType + => Value?.GetType(); + + } + public class MyExpandableIListConverter : ExpandableObjectConverter + { + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + if (value is IList list) + { + PropertyDescriptorCollection propDescriptions = new PropertyDescriptorCollection(null); + IEnumerator enumerator = list.GetEnumerator(); + int counter = -1; + while (enumerator.MoveNext()) + { + counter++; + propDescriptions.Add(new ListItemPropertyDescriptor(list, counter)); + + } + return propDescriptions; + } + else + { + return base.GetProperties(context, value, attributes); + } + } + } + + public static class TypeDecorationManager + { + public static void AddExpandableObjectConverter(Type T) + { + TypeDescriptor.AddAttributes(T, new TypeConverterAttribute(typeof(ExpandableObjectConverter))); + TypeDescriptor.AddAttributes(T, new ExpandableObjectAttribute()); + } + + public static void AddExpandableIListConverter(Type T) + { + TypeDescriptor.AddAttributes(T, new TypeConverterAttribute(typeof(MyExpandableIListConverter))); + TypeDescriptor.AddAttributes(T, new ExpandableObjectAttribute()); + } + } + public class SubclassFilterConverter : IValueConverter { public Type TargetType { get; set; }