diff --git a/src/FlaUInspect/Resources/RibbonIcons.xaml b/src/FlaUInspect/Resources/RibbonIcons.xaml index 6eca9c6..64a96ff 100644 --- a/src/FlaUInspect/Resources/RibbonIcons.xaml +++ b/src/FlaUInspect/Resources/RibbonIcons.xaml @@ -2,43 +2,47 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + - + - + - + - + @@ -46,155 +50,246 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/FlaUInspect/ViewModels/MainViewModel.cs b/src/FlaUInspect/ViewModels/MainViewModel.cs index 2cbdae8..e82861a 100644 --- a/src/FlaUInspect/ViewModels/MainViewModel.cs +++ b/src/FlaUInspect/ViewModels/MainViewModel.cs @@ -3,8 +3,10 @@ using System.Drawing; using System.Drawing.Imaging; using System.Reflection; +using System.Windows; using System.Windows.Data; using System.Windows.Input; +using System.Xml.Linq; using FlaUI.Core; using FlaUI.Core.AutomationElements; using FlaUI.Core.Identifiers; @@ -26,6 +28,8 @@ public class MainViewModel : ObservableObject { private AutomationBase? _automation; private RelayCommand? _captureSelectedItemCommand; private RelayCommand? _closeInfoCommand; + private RelayCommand? _copyDetailsToClipboardCommand; + private RelayCommand? _currentElementSaveStateCommand; private ObservableCollection? _elementPatterns = []; private FocusTrackingMode? _focusTrackingMode; private HoverMode? _hoverMode; @@ -180,6 +184,111 @@ public string? ApplicationVersion { IsInfoVisible = false; }); + public ICommand CurrentElementSaveStateCommand => _currentElementSaveStateCommand ??= new RelayCommand(_ => { + if (SelectedItem?.AutomationElement == null) { + return; + } + + try { + XDocument document = new (); + document.Add(new XElement("Root")); + ExportElement(document.Root!, SelectedItem); + + Clipboard.SetText(document.ToString()); + CopiedNotificationCurrentElementSaveStateRequested?.Invoke(); + } catch (Exception e) { + _logger?.LogError(e.ToString()); + } + }); + + public ICommand CollapseAllDetailsCommand => new RelayCommand(_ => { + foreach (ElementPatternItem pattern in ElementPatterns) { + pattern.IsExpanded = false; + } + }); + + public ICommand ExpandAllDetailsCommand => new RelayCommand(_ => { + foreach (ElementPatternItem pattern in ElementPatterns) { + pattern.IsExpanded = true; + } + }); + + public ICommand CopyDetailsToClipboardCommand => _copyDetailsToClipboardCommand ??= new RelayCommand(_ => { + if (SelectedItem?.AutomationElement == null) { + return; + } + + try { + XDocument document = new (); + document.Add(new XElement("Root")); + + foreach (ElementPatternItem elementPatternItem in ElementPatterns) { + XElement patternNode = new ("Pattern", + new XAttribute("Name", elementPatternItem.PatternName), + new XAttribute("Id", elementPatternItem.PatternIdName)); + + foreach (PatternItem patternItem in elementPatternItem.Children) { + XElement itemNode = new ("Item", + new XAttribute("Key", patternItem.Key), + new XAttribute("Value", patternItem.Value ?? string.Empty)); + patternNode.Add(itemNode); + } + + if (patternNode.HasElements) { + document.Root!.Add(patternNode); + } + } + Clipboard.SetText(document.ToString()); + CopiedNotificationRequested?.Invoke(); + } catch (Exception e) { + _logger?.LogError(e.ToString()); + } + }); + + public event Action? CopiedNotificationRequested; + public event Action? CopiedNotificationCurrentElementSaveStateRequested; + + private void ExportElement(XElement parent, ElementViewModel element) { + XElement xElement = CreateXElement(element); + parent.Add(xElement); + + try { + foreach (ElementViewModel children in element.Children!) { + try { + xElement.Add(CreateXElement(children!)); + } catch { + // ignored + } + } + + foreach (ElementViewModel children in element.Children.Where(x => x is { IsExpanded: true }).Where(x => x != null)!) { + try { + ExportElement(xElement, children!); + } catch { + // ignored + } + } + } catch { + // ignored + } + } + + private XElement CreateXElement(ElementViewModel element) { + + List attrs = [ + new ("Name", element.Name), + new ("AutomationId", element.AutomationId), + new ("ControlType", element.ControlType) + ]; + + if (EnableXPath) { + attrs.Add(new XAttribute("XPath", element.XPath)); + } + + XElement xElement = new ("Element", attrs); + return xElement; + } + private void ReadPatternsForSelectedItem(AutomationElement? selectedItemAutomationElement) { if (SelectedItem?.AutomationElement == null || selectedItemAutomationElement == null) { return; diff --git a/src/FlaUInspect/Views/MainWindow.xaml b/src/FlaUInspect/Views/MainWindow.xaml index 824f95d..1871b83 100644 --- a/src/FlaUInspect/Views/MainWindow.xaml +++ b/src/FlaUInspect/Views/MainWindow.xaml @@ -114,6 +114,28 @@ HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Horizontal"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/FlaUInspect/Views/MainWindow.xaml.cs b/src/FlaUInspect/Views/MainWindow.xaml.cs index 121e820..418b2f0 100644 --- a/src/FlaUInspect/Views/MainWindow.xaml.cs +++ b/src/FlaUInspect/Views/MainWindow.xaml.cs @@ -1,5 +1,6 @@ using System.Windows; using System.Windows.Controls; +using System.Windows.Media.Animation; using FlaUInspect.ViewModels; namespace FlaUInspect.Views; @@ -13,9 +14,19 @@ public MainWindow() { private void MainWindow_Loaded(object sender, EventArgs e) { if (DataContext is MainViewModel mainViewModel) { mainViewModel.Initialize(); + mainViewModel.CopiedNotificationRequested += ShowCopiedNotification; + mainViewModel.CopiedNotificationCurrentElementSaveStateRequested += ShowCopiedNotificationCurrentElementSaveStateRequested; } } + private async void ShowCopiedNotificationCurrentElementSaveStateRequested() { + CopiedNotificationCurrentElementSaveStateGrid.Visibility = Visibility.Visible; + var animation = new DoubleAnimation(1, 0, TimeSpan.FromSeconds(1)); + CopiedNotificationCurrentElementSaveStateGrid.BeginAnimation(UIElement.OpacityProperty, animation); + await Task.Delay(1000); + CopiedNotificationCurrentElementSaveStateGrid.Visibility = Visibility.Collapsed; + } + private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) { if (DataContext is MainViewModel mainViewModel) { mainViewModel.SelectedItem = e.NewValue as ElementViewModel; @@ -36,4 +47,12 @@ private void InvokePatternActionHandler(object sender, RoutedEventArgs e) { }); } } + + private async void ShowCopiedNotification() { + CopiedNotificationGrid.Visibility = Visibility.Visible; + var animation = new DoubleAnimation(1, 0, TimeSpan.FromSeconds(1)); + CopiedNotificationGrid.BeginAnimation(UIElement.OpacityProperty, animation); + await Task.Delay(1000); + CopiedNotificationGrid.Visibility = Visibility.Collapsed; + } } \ No newline at end of file