Melhorias na usabilidade e interação com o GridView
Substituído duplo-clique por botão para abrir pastas, adicionada nova coluna com ícone de pasta e handler `OpenFolderButton_Click`. Células agora usam `TextBox` readonly para permitir seleção de texto. Melhorado o comando de cópia (`Ctrl+C`) com tratamento de exceções e mensagens de erro detalhadas. Refatorado hit-test para suportar a nova estrutura de células e adicionado fallback para capturar texto de outras fontes. Ajustado evento `KeyDown` para abrir pastas com validações adicionais. Melhorias gerais na robustez e mensagens informativas ao usuário.
This commit is contained in:
parent
6b791aa3d5
commit
2f1c28e482
106
MainWindow.xaml
106
MainWindow.xaml
@ -88,11 +88,13 @@
|
|||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Text="{Binding SearchUnidadeText, UpdateSourceTrigger=PropertyChanged}" />
|
Text="{Binding SearchUnidadeText, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<TextBlock Text="Unidades da empresa selecionada (Duplo-clique para abrir pasta):" Margin="10,0,10,0" FontWeight="Bold" Grid.Row="1"/>
|
<!-- texto atualizado: remove menção ao duplo-clique -->
|
||||||
|
<TextBlock Text="Unidades da empresa selecionada (Clique no ícone da pasta para abrir o caminho):" Margin="10,0,10,0" FontWeight="Bold" Grid.Row="1"/>
|
||||||
|
|
||||||
<ListView ItemsSource="{Binding UnidadesSelecionadas}" Margin="10" Grid.Row="2"
|
<ListView ItemsSource="{Binding UnidadesSelecionadas}" Margin="10" Grid.Row="2"
|
||||||
x:Name="UnidadesListView"
|
x:Name="UnidadesListView"
|
||||||
PreviewMouseLeftButtonDown="UnidadesListView_PreviewMouseLeftButtonDown"
|
PreviewMouseLeftButtonDown="UnidadesListView_PreviewMouseLeftButtonDown"
|
||||||
PreviewMouseRightButtonDown="UnidadesListView_PreviewMouseRightButtonDown">
|
PreviewMouseRightButtonDown="UnidadesListView_PreviewMouseRightButtonDown">
|
||||||
<ListView.InputBindings>
|
<ListView.InputBindings>
|
||||||
<KeyBinding Key="C" Modifiers="Control" Command="ApplicationCommands.Copy"/>
|
<KeyBinding Key="C" Modifiers="Control" Command="ApplicationCommands.Copy"/>
|
||||||
</ListView.InputBindings>
|
</ListView.InputBindings>
|
||||||
@ -104,21 +106,107 @@
|
|||||||
<MenuItem Header="Copiar coluna" Click="CopyMenu_Click"/>
|
<MenuItem Header="Copiar coluna" Click="CopyMenu_Click"/>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</ListView.ContextMenu>
|
</ListView.ContextMenu>
|
||||||
|
|
||||||
<ListView.View>
|
<ListView.View>
|
||||||
<GridView>
|
<GridView>
|
||||||
<GridViewColumn Header="Unidade" DisplayMemberBinding="{Binding Unidade}" Width="200" />
|
<!-- Coluna do ícone de pasta (pequena) -->
|
||||||
<GridViewColumn Header="Instalação" DisplayMemberBinding="{Binding Codigo_Instalacao}" Width="120" />
|
<GridViewColumn Width="36" Header="">
|
||||||
<GridViewColumn Header="CNPJ" DisplayMemberBinding="{Binding CNPJ_CPF}" Width="120" />
|
<GridViewColumn.CellTemplate>
|
||||||
<GridViewColumn Header="Razão Social" DisplayMemberBinding="{Binding Razao_Social}" Width="Auto" />
|
<DataTemplate>
|
||||||
|
<!-- Botão com ícone (emoji) — simples e confiável.
|
||||||
|
Pode trocar por uma imagem se preferir (Image/Path). -->
|
||||||
|
<Button Click="OpenFolderButton_Click"
|
||||||
|
ToolTip="Abrir pasta da unidade"
|
||||||
|
Padding="2"
|
||||||
|
Margin="2"
|
||||||
|
BorderThickness="0"
|
||||||
|
Background="Transparent"
|
||||||
|
Cursor="Hand"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
DataContext="{Binding}">
|
||||||
|
<TextBlock Text="📁" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||||
|
</Button>
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
|
||||||
|
<!-- Demais colunas (TextBox readonly para seleção) -->
|
||||||
|
<GridViewColumn Header="Unidade" Width="200">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBox Text="{Binding Unidade}"
|
||||||
|
IsReadOnly="True"
|
||||||
|
BorderThickness="0"
|
||||||
|
Background="Transparent"
|
||||||
|
Padding="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Cursor="IBeam"
|
||||||
|
Focusable="True"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
|
||||||
|
<GridViewColumn Header="Instalação" Width="120">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBox Text="{Binding Codigo_Instalacao}"
|
||||||
|
IsReadOnly="True"
|
||||||
|
BorderThickness="0"
|
||||||
|
Background="Transparent"
|
||||||
|
Padding="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Cursor="IBeam"
|
||||||
|
Focusable="True"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
|
||||||
|
<GridViewColumn Header="CNPJ" Width="120">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBox Text="{Binding CNPJ_CPF}"
|
||||||
|
IsReadOnly="True"
|
||||||
|
BorderThickness="0"
|
||||||
|
Background="Transparent"
|
||||||
|
Padding="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Cursor="IBeam"
|
||||||
|
Focusable="True"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
|
||||||
|
<GridViewColumn Header="Razão Social" Width="Auto">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBox Text="{Binding Razao_Social}"
|
||||||
|
IsReadOnly="True"
|
||||||
|
BorderThickness="0"
|
||||||
|
Background="Transparent"
|
||||||
|
Padding="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Cursor="IBeam"
|
||||||
|
Focusable="True"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
</GridView>
|
</GridView>
|
||||||
</ListView.View>
|
</ListView.View>
|
||||||
|
|
||||||
<ListView.ItemContainerStyle>
|
<ListView.ItemContainerStyle>
|
||||||
<Style TargetType="ListViewItem">
|
<Style TargetType="ListViewItem">
|
||||||
<EventSetter Event="MouseDoubleClick" Handler="UnidadeListView_MouseDoubleClick" />
|
<!-- removido MouseDoubleClick -->
|
||||||
|
<!--<EventSetter Event="MouseDoubleClick" Handler="UnidadeListView_MouseDoubleClick" />-->
|
||||||
<EventSetter Event="KeyDown" Handler="UnidadeListView_EnterKeyDown" />
|
<EventSetter Event="KeyDown" Handler="UnidadeListView_EnterKeyDown" />
|
||||||
</Style>
|
</Style>
|
||||||
</ListView.ItemContainerStyle>
|
</ListView.ItemContainerStyle>
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
@ -47,19 +47,27 @@ namespace BD_empresa
|
|||||||
if (sender is ListView lv)
|
if (sender is ListView lv)
|
||||||
{
|
{
|
||||||
var pt = e.GetPosition(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 hit = VisualTreeHelper.HitTest(lv, pt);
|
||||||
var dep = hit?.VisualHit;
|
var dep = hit?.VisualHit;
|
||||||
|
if (dep == null) return;
|
||||||
|
|
||||||
|
// Seleciona o item clicado
|
||||||
var lvi = FindAncestor<ListViewItem>(dep);
|
var lvi = FindAncestor<ListViewItem>(dep);
|
||||||
if (lvi != null)
|
if (lvi != null) lvi.IsSelected = true;
|
||||||
{
|
|
||||||
lvi.IsSelected = true;
|
// Se certo elemento TextBox foi clicado, foca ele (para permitir seleção/Ctrl+C)
|
||||||
}
|
var tbx = FindAncestor<TextBox>(dep) ?? FindDescendant<TextBox>(dep);
|
||||||
|
tbx?.Focus();
|
||||||
|
|
||||||
RecordCellTextFromPoint(lv, pt);
|
RecordCellTextFromPoint(lv, pt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UnidadesListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_lastClickedCellText = null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executado quando o usuário pressiona Ctrl+C
|
/// Executado quando o usuário pressiona Ctrl+C
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -88,7 +96,14 @@ namespace BD_empresa
|
|||||||
// 1) se o usuário clicou previamente em uma célula (direito/esquerdo), usamos esse texto
|
// 1) se o usuário clicou previamente em uma célula (direito/esquerdo), usamos esse texto
|
||||||
if (!string.IsNullOrEmpty(_lastClickedCellText))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +121,14 @@ namespace BD_empresa
|
|||||||
if (prop != null)
|
if (prop != null)
|
||||||
{
|
{
|
||||||
var value = prop.GetValue(unidade)?.ToString() ?? string.Empty;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,13 +137,27 @@ namespace BD_empresa
|
|||||||
var tb = FindDescendant<TextBlock>(lvi);
|
var tb = FindDescendant<TextBlock>(lvi);
|
||||||
if (tb != null)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) fallback final: ToString do objeto
|
// 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;
|
var dep = hit?.VisualHit;
|
||||||
if (dep == null) return;
|
if (dep == null) return;
|
||||||
|
|
||||||
// sobe a árvore procurando TextBlock (geralmente GridView cria TextBlock)
|
// 1) Procura TextBox (nossa célula agora é TextBox readonly)
|
||||||
var tb = FindAncestor<TextBlock>(dep);
|
var tbx = FindAncestor<TextBox>(dep) ?? FindDescendant<TextBox>(dep);
|
||||||
if (tb != null)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// às vezes o TextBlock está abaixo de um Border/ContentPresenter
|
// 2) Procura TextBlock (fallback)
|
||||||
|
var tblock = FindAncestor<TextBlock>(dep) ?? FindDescendant<TextBlock>(dep);
|
||||||
|
if (tblock != null)
|
||||||
|
{
|
||||||
|
_lastClickedCellText = tblock.Text;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Fallback: procura container e, dentro dele, tenta TextBox primeiro, depois TextBlock
|
||||||
DependencyObject? container = FindAncestor<ContentPresenter>(dep);
|
DependencyObject? container = FindAncestor<ContentPresenter>(dep);
|
||||||
container ??= FindAncestor<GridViewRowPresenter>(dep);
|
container ??= FindAncestor<GridViewRowPresenter>(dep);
|
||||||
|
|
||||||
if (container != null)
|
if (container != null)
|
||||||
{
|
{
|
||||||
var tb2 = FindDescendant<TextBlock>(container);
|
var innerTbx = FindDescendant<TextBox>(container);
|
||||||
if (tb2 != null)
|
if (innerTbx != null)
|
||||||
{
|
{
|
||||||
_lastClickedCellText = tb2.Text;
|
_lastClickedCellText = !string.IsNullOrEmpty(innerTbx.SelectedText) ? innerTbx.SelectedText : innerTbx.Text;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var innerTblock = FindDescendant<TextBlock>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
// Helpers (coloque-os se já não existirem):
|
||||||
/// Encontra primeiro ancestral do tipo T.
|
|
||||||
/// </summary>
|
|
||||||
private static T? FindAncestor<T>(DependencyObject? current) where T : DependencyObject
|
private static T? FindAncestor<T>(DependencyObject? current) where T : DependencyObject
|
||||||
{
|
{
|
||||||
while (current != null)
|
while (current != null)
|
||||||
@ -171,9 +244,6 @@ namespace BD_empresa
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encontra primeiro descendente do tipo T usando DFS (útil para achar TextBlock dentro de um visual container)
|
|
||||||
/// </summary>
|
|
||||||
private static T? FindDescendant<T>(DependencyObject? root) where T : DependencyObject
|
private static T? FindDescendant<T>(DependencyObject? root) where T : DependencyObject
|
||||||
{
|
{
|
||||||
if (root == null) return null;
|
if (root == null) return null;
|
||||||
@ -192,6 +262,7 @@ namespace BD_empresa
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
txtEmpresaSearch.Focus();
|
txtEmpresaSearch.Focus();
|
||||||
@ -218,22 +289,110 @@ namespace BD_empresa
|
|||||||
}
|
}
|
||||||
private void UnidadeListView_EnterKeyDown(object sender, KeyEventArgs e)
|
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);
|
MessageBox.Show($"O caminho informado não existe: {caminho}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
return;
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
MessageBox.Show($"Não foi possível abrir a pasta: {ex.Message}", "Erro", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user