diff --git a/MainWindow.xaml b/MainWindow.xaml index 5b096a5..5cbb1db 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -88,11 +88,13 @@ Grid.Column="2" Text="{Binding SearchUnidadeText, UpdateSourceTrigger=PropertyChanged}" /> - + + + + x:Name="UnidadesListView" + PreviewMouseLeftButtonDown="UnidadesListView_PreviewMouseLeftButtonDown" + PreviewMouseRightButtonDown="UnidadesListView_PreviewMouseRightButtonDown"> @@ -104,21 +106,107 @@ + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index d5d1bb2..331f1f0 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -47,19 +47,27 @@ namespace BD_empresa if (sender is ListView lv) { var pt = e.GetPosition(lv); - // Se clicou em um ListViewItem, seleciona-o (comportamento útil para context menu) var hit = VisualTreeHelper.HitTest(lv, pt); var dep = hit?.VisualHit; + if (dep == null) return; + + // Seleciona o item clicado var lvi = FindAncestor(dep); - if (lvi != null) - { - lvi.IsSelected = true; - } + if (lvi != null) lvi.IsSelected = true; + + // Se certo elemento TextBox foi clicado, foca ele (para permitir seleção/Ctrl+C) + var tbx = FindAncestor(dep) ?? FindDescendant(dep); + tbx?.Focus(); RecordCellTextFromPoint(lv, pt); } } + private void UnidadesListView_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + _lastClickedCellText = null; + } + /// /// Executado quando o usuário pressiona Ctrl+C /// @@ -88,7 +96,14 @@ namespace BD_empresa // 1) se o usuário clicou previamente em uma célula (direito/esquerdo), usamos esse texto if (!string.IsNullOrEmpty(_lastClickedCellText)) { - Clipboard.SetText(_lastClickedCellText); + try + { + Clipboard.SetText(_lastClickedCellText); + } + catch (Exception ex) +{ + MessageBox.Show($"Erro ao copiar para o clipboard: {ex.Message}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + } return; } @@ -106,7 +121,14 @@ namespace BD_empresa if (prop != null) { var value = prop.GetValue(unidade)?.ToString() ?? string.Empty; - Clipboard.SetText(value); + try + { + Clipboard.SetText(value); + } + catch (Exception ex) + { + MessageBox.Show($"Erro ao copiar para o clipboard: {ex.Message}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + } return; } } @@ -115,13 +137,27 @@ namespace BD_empresa var tb = FindDescendant(lvi); if (tb != null) { - Clipboard.SetText(tb.Text); + try + { + Clipboard.SetText(tb.Text); + } + catch (Exception ex) + { + MessageBox.Show($"Erro ao copiar para o clipboard: {ex.Message}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + } return; } } // 3) fallback final: ToString do objeto - Clipboard.SetText(unidade?.ToString() ?? string.Empty); + try + { + Clipboard.SetText(unidade?.ToString() ?? string.Empty); + } + catch (Exception ex) + { + MessageBox.Show($"Erro ao copiar para o clipboard: {ex.Message}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + } } } @@ -136,31 +172,68 @@ namespace BD_empresa var dep = hit?.VisualHit; if (dep == null) return; - // sobe a árvore procurando TextBlock (geralmente GridView cria TextBlock) - var tb = FindAncestor(dep); - if (tb != null) + // 1) Procura TextBox (nossa célula agora é TextBox readonly) + var tbx = FindAncestor(dep) ?? FindDescendant(dep); + if (tbx != null) { - _lastClickedCellText = tb.Text; + // se houver seleção, prioriza a seleção + if (!string.IsNullOrEmpty(tbx.SelectedText)) + _lastClickedCellText = tbx.SelectedText; + else + _lastClickedCellText = tbx.Text; return; } - // às vezes o TextBlock está abaixo de um Border/ContentPresenter + // 2) Procura TextBlock (fallback) + var tblock = FindAncestor(dep) ?? FindDescendant(dep); + if (tblock != null) + { + _lastClickedCellText = tblock.Text; + return; + } + + // 3) Fallback: procura container e, dentro dele, tenta TextBox primeiro, depois TextBlock DependencyObject? container = FindAncestor(dep); container ??= FindAncestor(dep); if (container != null) { - var tb2 = FindDescendant(container); - if (tb2 != null) + var innerTbx = FindDescendant(container); + if (innerTbx != null) { - _lastClickedCellText = tb2.Text; + _lastClickedCellText = !string.IsNullOrEmpty(innerTbx.SelectedText) ? innerTbx.SelectedText : innerTbx.Text; + return; + } + + var innerTblock = FindDescendant(container); + if (innerTblock != null) + { + _lastClickedCellText = innerTblock.Text; + return; + } + } + + // 4) último recurso: se um ListViewItem foi selecionado, tenta pegar a primeira coluna via binding (fallback anterior) + if (listView.SelectedItem is Data.UnidadeSmart unidade) + { + var gv = listView.View as GridView; + if (gv?.Columns.Count > 0) + { + var firstCol = gv.Columns[0]; + if (firstCol.DisplayMemberBinding is System.Windows.Data.Binding b && !string.IsNullOrEmpty(b.Path?.Path)) + { + var prop = unidade.GetType().GetProperty(b.Path.Path, BindingFlags.Public | BindingFlags.Instance); + if (prop != null) + { + var value = prop.GetValue(unidade)?.ToString() ?? string.Empty; + _lastClickedCellText = value; + } + } } } } - /// - /// Encontra primeiro ancestral do tipo T. - /// + // Helpers (coloque-os se já não existirem): private static T? FindAncestor(DependencyObject? current) where T : DependencyObject { while (current != null) @@ -171,9 +244,6 @@ namespace BD_empresa return null; } - /// - /// Encontra primeiro descendente do tipo T usando DFS (útil para achar TextBlock dentro de um visual container) - /// private static T? FindDescendant(DependencyObject? root) where T : DependencyObject { if (root == null) return null; @@ -192,6 +262,7 @@ namespace BD_empresa } return null; } + private void Window_Loaded(object sender, RoutedEventArgs e) { txtEmpresaSearch.Focus(); @@ -218,22 +289,110 @@ namespace BD_empresa } private void UnidadeListView_EnterKeyDown(object sender, KeyEventArgs e) { - if (e.Key == Key.Enter && sender is ListViewItem listViewItem && listViewItem.Content is Data.UnidadeSmart unidade && !string.IsNullOrWhiteSpace(unidade.Caminho_NFs)) + try { - string? parentDirectory = System.IO.Path.GetDirectoryName(unidade.Caminho_NFs); + if (e.Key != Key.Enter) { return; } - if (!string.IsNullOrWhiteSpace(parentDirectory)) + // DataContext do Button será a UnidadeSmart relacionada à linha + var lvi = sender as ListViewItem; + if (lvi?.Content is not Data.UnidadeSmart unidade) { - try + MessageBox.Show("Não foi possível identificar a unidade.", "Erro", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + var caminho = unidade.Caminho_NFs; + if (string.IsNullOrWhiteSpace(caminho)) + { + MessageBox.Show("Não há caminho definido para essa unidade.", "Aviso", MessageBoxButton.OK, MessageBoxImage.Information); + return; + } + + string folderToOpen; + // Se o caminho for um arquivo (provavelmente um arquivo NFe), abre o diretório pai. + if (System.IO.File.Exists(caminho)) + { + folderToOpen = System.IO.Path.GetDirectoryName(caminho) ?? caminho; + } + else + { + // tenta obter diretório do caminho (caso usuário tenha colocado um arquivo inexistente ou caminho parcial) + var parent = System.IO.Path.GetDirectoryName(caminho); + if (!string.IsNullOrWhiteSpace(parent) && System.IO.Directory.Exists(parent)) + folderToOpen = parent; + else { - System.Diagnostics.Process.Start("explorer.exe", unidade.Caminho_NFs); - } - catch (System.Exception ex) - { - MessageBox.Show($"Não foi possível abrir a pasta: {ex.Message}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show($"O caminho informado não existe: {caminho}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + return; } } + + // Abre o Explorer na pasta encontrada (UseShellExecute = true para abrir paths corretamente) + var psi = new System.Diagnostics.ProcessStartInfo + { + FileName = "explorer.exe", + Arguments = $"\"{folderToOpen}\"", + UseShellExecute = true + }; + System.Diagnostics.Process.Start(psi); + } + catch (System.Exception ex) + { + MessageBox.Show($"Não foi possível abrir a pasta: {ex.Message}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); } } + private void OpenFolderButton_Click(object sender, RoutedEventArgs e) + { + try + { + // DataContext do Button será a UnidadeSmart relacionada à linha + var btn = sender as Button; + if (btn?.DataContext is not Data.UnidadeSmart unidade) + { + MessageBox.Show("Não foi possível identificar a unidade.", "Erro", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + var caminho = unidade.Caminho_NFs; + if (string.IsNullOrWhiteSpace(caminho)) + { + MessageBox.Show("Não há caminho definido para essa unidade.", "Aviso", MessageBoxButton.OK, MessageBoxImage.Information); + return; + } + + string folderToOpen; + // Se o caminho for um arquivo (provavelmente um arquivo NFe), abre o diretório pai. + if (System.IO.File.Exists(caminho)) + { + folderToOpen = System.IO.Path.GetDirectoryName(caminho) ?? caminho; + } + else + { + // tenta obter diretório do caminho (caso usuário tenha colocado um arquivo inexistente ou caminho parcial) + var parent = System.IO.Path.GetDirectoryName(caminho); + if (!string.IsNullOrWhiteSpace(parent) && System.IO.Directory.Exists(parent)) + folderToOpen = parent; + else + { + MessageBox.Show($"O caminho informado não existe: {caminho}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + } + + // Abre o Explorer na pasta encontrada (UseShellExecute = true para abrir paths corretamente) + var psi = new System.Diagnostics.ProcessStartInfo + { + FileName = "explorer.exe", + Arguments = $"\"{folderToOpen}\"", + UseShellExecute = true + }; + System.Diagnostics.Process.Start(psi); + } + catch (System.Exception ex) + { + MessageBox.Show($"Não foi possível abrir a pasta: {ex.Message}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + } } \ No newline at end of file