Skip to content

Commit 253c830

Browse files
authored
feat(connection): implement delete connection functionality (#323)
1 parent e8339b9 commit 253c830

File tree

5 files changed

+104
-31
lines changed

5 files changed

+104
-31
lines changed

src/CodingWithCalvin.CouchbaseExplorer/CodingWithCalvin.CouchbaseExplorer.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
<Compile Include="Services\ConnectionSettingsService.cs" />
8080
<Compile Include="Services\CouchbaseService.cs" />
8181
<Compile Include="Services\CredentialManagerService.cs" />
82+
<Compile Include="ViewModels\BindingProxy.cs" />
8283
<Compile Include="ViewModels\BucketNode.cs" />
8384
<Compile Include="ViewModels\BucketsFolderNode.cs" />
8485
<Compile Include="ViewModels\CollectionNode.cs" />

src/CodingWithCalvin.CouchbaseExplorer/CouchbaseExplorerWindowControl.xaml

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<!-- Count to Visibility Converter (shows when count is 0) -->
2525
<vm:CountToVisibilityConverter x:Key="CountToVisibilityConverter" />
2626

27+
<!-- Binding Proxy to access ViewModel from ContextMenus (which exist outside the visual tree) -->
28+
<vm:BindingProxy x:Key="ViewModelProxy" Data="{Binding}" />
29+
2730
<!-- TreeView Item Style for proper selection binding -->
2831
<Style TargetType="TreeViewItem">
2932
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
@@ -248,13 +251,13 @@
248251
<Setter Property="ContextMenu">
249252
<Setter.Value>
250253
<ContextMenu>
251-
<MenuItem Header="Connect" Command="{Binding DataContext.ConnectCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
252-
<MenuItem Header="Disconnect" Command="{Binding DataContext.DisconnectCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
254+
<MenuItem Header="Connect" Command="{Binding Data.ConnectCommand, Source={StaticResource ViewModelProxy}}" />
255+
<MenuItem Header="Disconnect" Command="{Binding Data.DisconnectCommand, Source={StaticResource ViewModelProxy}}" />
253256
<Separator />
254-
<MenuItem Header="Refresh" Command="{Binding DataContext.RefreshCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
257+
<MenuItem Header="Refresh" Command="{Binding Data.RefreshCommand, Source={StaticResource ViewModelProxy}}" />
255258
<Separator />
256-
<MenuItem Header="Edit Connection..." Command="{Binding DataContext.EditConnectionCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
257-
<MenuItem Header="Delete Connection" Command="{Binding DataContext.DeleteConnectionCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
259+
<MenuItem Header="Edit Connection..." Command="{Binding Data.EditConnectionCommand, Source={StaticResource ViewModelProxy}}" />
260+
<MenuItem Header="Delete Connection" Command="{Binding Data.DeleteConnectionCommand, Source={StaticResource ViewModelProxy}}" />
258261
</ContextMenu>
259262
</Setter.Value>
260263
</Setter>
@@ -263,7 +266,7 @@
263266
<Setter Property="ContextMenu">
264267
<Setter.Value>
265268
<ContextMenu>
266-
<MenuItem Header="Refresh" Command="{Binding DataContext.RefreshCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
269+
<MenuItem Header="Refresh" Command="{Binding Data.RefreshCommand, Source={StaticResource ViewModelProxy}}" />
267270
</ContextMenu>
268271
</Setter.Value>
269272
</Setter>
@@ -272,7 +275,7 @@
272275
<Setter Property="ContextMenu">
273276
<Setter.Value>
274277
<ContextMenu>
275-
<MenuItem Header="Refresh" Command="{Binding DataContext.RefreshCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
278+
<MenuItem Header="Refresh" Command="{Binding Data.RefreshCommand, Source={StaticResource ViewModelProxy}}" />
276279
</ContextMenu>
277280
</Setter.Value>
278281
</Setter>
@@ -281,9 +284,9 @@
281284
<Setter Property="ContextMenu">
282285
<Setter.Value>
283286
<ContextMenu>
284-
<MenuItem Header="New Document..." Command="{Binding DataContext.NewDocumentCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
287+
<MenuItem Header="New Document..." Command="{Binding Data.NewDocumentCommand, Source={StaticResource ViewModelProxy}}" />
285288
<Separator />
286-
<MenuItem Header="Refresh" Command="{Binding DataContext.RefreshCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
289+
<MenuItem Header="Refresh" Command="{Binding Data.RefreshCommand, Source={StaticResource ViewModelProxy}}" />
287290
</ContextMenu>
288291
</Setter.Value>
289292
</Setter>
@@ -292,11 +295,11 @@
292295
<Setter Property="ContextMenu">
293296
<Setter.Value>
294297
<ContextMenu>
295-
<MenuItem Header="Open" Command="{Binding DataContext.OpenDocumentCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
298+
<MenuItem Header="Open" Command="{Binding Data.OpenDocumentCommand, Source={StaticResource ViewModelProxy}}" />
296299
<Separator />
297-
<MenuItem Header="Copy Document ID" Command="{Binding DataContext.CopyDocumentIdCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
300+
<MenuItem Header="Copy Document ID" Command="{Binding Data.CopyDocumentIdCommand, Source={StaticResource ViewModelProxy}}" />
298301
<Separator />
299-
<MenuItem Header="Delete" Command="{Binding DataContext.DeleteDocumentCommand, RelativeSource={RelativeSource AncestorType=TreeView}}" />
302+
<MenuItem Header="Delete" Command="{Binding Data.DeleteDocumentCommand, Source={StaticResource ViewModelProxy}}" />
300303
</ContextMenu>
301304
</Setter.Value>
302305
</Setter>

src/CodingWithCalvin.CouchbaseExplorer/CouchbaseExplorerWindowControl.xaml.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
using System.Windows;
12
using System.Windows.Controls;
3+
using System.Windows.Input;
4+
using System.Windows.Media;
25
using CodingWithCalvin.CouchbaseExplorer.ViewModels;
36

47
namespace CodingWithCalvin.CouchbaseExplorer
@@ -15,14 +18,39 @@ public CouchbaseExplorerWindowControl()
1518
InitializeComponent();
1619

1720
ExplorerTreeView.SelectedItemChanged += OnSelectedItemChanged;
21+
ExplorerTreeView.PreviewMouseRightButtonDown += OnPreviewMouseRightButtonDown;
1822
}
1923

20-
private void OnSelectedItemChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<object> e)
24+
private void OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
2125
{
2226
if (e.NewValue is TreeNodeBase node)
2327
{
2428
ViewModel.SelectedNode = node;
2529
}
2630
}
31+
32+
private void OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
33+
{
34+
var treeViewItem = FindAncestor<TreeViewItem>((DependencyObject)e.OriginalSource);
35+
if (treeViewItem != null)
36+
{
37+
treeViewItem.Focus();
38+
treeViewItem.IsSelected = true;
39+
e.Handled = true;
40+
}
41+
}
42+
43+
private static T FindAncestor<T>(DependencyObject current) where T : DependencyObject
44+
{
45+
while (current != null)
46+
{
47+
if (current is T result)
48+
{
49+
return result;
50+
}
51+
current = VisualTreeHelper.GetParent(current);
52+
}
53+
return null;
54+
}
2755
}
2856
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System.Windows;
2+
3+
namespace CodingWithCalvin.CouchbaseExplorer.ViewModels
4+
{
5+
/// <summary>
6+
/// A proxy class that allows binding to a DataContext from outside the visual tree.
7+
/// This is commonly used for ContextMenus, Popups, and other elements that exist
8+
/// in a separate visual tree.
9+
/// </summary>
10+
public class BindingProxy : Freezable
11+
{
12+
public static readonly DependencyProperty DataProperty =
13+
DependencyProperty.Register(
14+
nameof(Data),
15+
typeof(object),
16+
typeof(BindingProxy),
17+
new UIPropertyMetadata(null));
18+
19+
public object Data
20+
{
21+
get => GetValue(DataProperty);
22+
set => SetValue(DataProperty, value);
23+
}
24+
25+
protected override Freezable CreateInstanceCore()
26+
{
27+
return new BindingProxy();
28+
}
29+
}
30+
}

src/CodingWithCalvin.CouchbaseExplorer/ViewModels/CouchbaseExplorerViewModel.cs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -336,35 +336,46 @@ private void OnEditConnection(object parameter)
336336
}
337337
}
338338

339-
private void OnDeleteConnection(object parameter)
339+
private async void OnDeleteConnection(object parameter)
340340
{
341-
if (SelectedNode is ConnectionNode connection)
341+
var connection = parameter as ConnectionNode ?? SelectedNode as ConnectionNode;
342+
if (connection == null)
342343
{
343-
var result = MessageBox.Show(
344-
$"Are you sure you want to delete the connection '{connection.Name}'?",
345-
"Delete Connection",
346-
MessageBoxButton.YesNo,
347-
MessageBoxImage.Warning);
344+
return;
345+
}
348346

349-
if (result == MessageBoxResult.Yes)
347+
var result = MessageBox.Show(
348+
$"Are you sure you want to delete the connection '{connection.Name}'?",
349+
"Delete Connection",
350+
MessageBoxButton.YesNo,
351+
MessageBoxImage.Warning);
352+
353+
if (result == MessageBoxResult.Yes)
354+
{
355+
// Disconnect first if connected
356+
if (connection.IsConnected)
350357
{
351-
// Disconnect first if connected
352-
if (connection.IsConnected)
353-
{
354-
// TODO: Disconnect from cluster
355-
connection.IsConnected = false;
356-
}
358+
await CouchbaseService.DisconnectAsync(connection.Id);
359+
connection.IsConnected = false;
360+
}
357361

358-
_settingsService.DeleteConnection(connection.Id);
362+
// Unsubscribe from events
363+
connection.ConnectRequested -= OnConnectRequested;
359364

360-
Connections.Remove(connection);
361-
}
365+
// Delete saved password
366+
CredentialManagerService.DeletePassword(connection.Id);
367+
368+
// Delete from settings
369+
_settingsService.DeleteConnection(connection.Id);
370+
371+
// Remove from UI
372+
Connections.Remove(connection);
362373
}
363374
}
364375

365376
private bool IsConnectionSelected(object parameter)
366377
{
367-
return SelectedNode is ConnectionNode;
378+
return parameter is ConnectionNode || SelectedNode is ConnectionNode;
368379
}
369380

370381
private void OnNewDocument(object parameter)

0 commit comments

Comments
 (0)