clear most of IDisposable infection from ViewModels
MODIFY
WalletWasabi.Dependencies/AvalonStudio.Shell
WalletWasabi.Dependencies/AvalonStudio.Shell
-Subproject commit 8163735bc84048eccc15f0cf30d71823f34ae495
+Subproject commit 9beb48373b9fc3c33d058a42c04f66a4f30bd90f

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
@@ -57,7 +57,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
CoordinatorFeePercent = registrableRound?.State?.CoordinatorFeePercent.ToString() ?? "0.003";
- CoinsList = new CoinListViewModel().DisposeWith(Disposables);
+ CoinsList = new CoinListViewModel();
AmountQueued = Money.Zero; // Global.ChaumianClient.State.SumAllQueuedCoinAmounts();
@@ -510,33 +510,18 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
public ReactiveCommand PrivacyStrongCommand { get; }
public ReactiveCommand TargetButtonCommand { get; }
- #region IDisposable Support
-
- protected override void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
+ public override void OnOpen()
{
- if (Global.ChaumianClient != null)
- {
- Global.ChaumianClient.CoinQueued -= ChaumianClient_CoinQueued;
- Global.ChaumianClient.CoinDequeued -= ChaumianClient_CoinDequeued;
- Global.ChaumianClient.StateUpdated -= ChaumianClient_StateUpdated;
- }
+ CoinsList.OnOpen();
- if (_coinsList != null)
- {
- _coinsList.DequeueCoinsPressed -= CoinsList_DequeueCoinsPressedAsync;
- }
+ base.OnOpen();
}
- base.Dispose(disposing);
+ public override bool OnClose()
+ {
+ CoinsList.OnClose();
- _disposedValue = true;
- }
+ return base.OnClose();
}
-
- #endregion IDisposable Support
}
}

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinListView.xaml
WalletWasabi.Gui/Controls/WalletExplorer/CoinListView.xaml
<DataTemplate>
<Grid>
<Expander Name="coinExpander" ExpandDirection="Down" Classes="coloredExpander" Background="{Binding ElementName=coinExpander, Path=IsExpanded, Converter={StaticResource CoinItemExpanderColorConverter}}">
-
- <StackPanel>
<Grid HorizontalAlignment="Left" ColumnDefinitions="150, *" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto" MaxWidth="800" Margin="35 10 0 25">
<TextBlock Text="Transaction Id:" Grid.Row="0" />
<controls:ExtendedTextBox Classes="selectableTextBlock Transaparent" Text="{Binding TransactionId}" Background="Transparent" Grid.Column="1" Grid.Row="0" />
<TextBlock Text="Public Key:" Grid.Row="7" />
<controls:ExtendedTextBox Classes="selectableTextBlock Transaparent" Text="{Binding PubKey}" Grid.Column="1" Grid.Row="7" />
</Grid>
- </StackPanel>
</Expander>
<Grid Margin="30 0 0 0" VerticalAlignment="Top">

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
@@ -19,11 +19,13 @@ using System.Reactive.Disposables;
namespace WalletWasabi.Gui.Controls.WalletExplorer
{
- public class CoinListViewModel : ViewModelBase, IDisposable
+ public class CoinListViewModel : ViewModelBase
{
- private CompositeDisposable Disposables { get; }
+ private CompositeDisposable _disposables;
- private readonly ReadOnlyObservableCollection<CoinViewModel> _coinViewModels;
+ public SourceList<CoinViewModel> RootList { get; private set; }
+
+ private ReadOnlyObservableCollection<CoinViewModel> _coinViewModels;
private SortExpressionComparer<CoinViewModel> _myComparer;
private CoinViewModel _selectedCoin;
@@ -149,8 +151,6 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
set => this.RaiseAndSetIfChanged(ref _coinJoinStatusWidth, value);
}
- public SourceList<CoinViewModel> RootList { get; }
-
private bool? GetCheckBoxesSelectedState(Func<CoinViewModel, bool> coinFilterPredicate)
{
var coins = Coins.Where(coinFilterPredicate).ToArray();
@@ -184,81 +184,17 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
public CoinListViewModel()
{
- Disposables = new CompositeDisposable();
-
- RemovedCoinViewModels = new List<CoinViewModel>();
- AmountSortDirection = SortOrder.Decreasing;
- RefreshOrdering();
-
- var sortChanged = this.WhenValueChanged(@this => MyComparer).Select(_ => MyComparer);
-
- RootList = new SourceList<CoinViewModel>().DisposeWith(Disposables);
- RootList.Connect()
- .OnItemAdded(cvm => cvm.PropertyChanged += Coin_PropertyChanged)
- .OnItemRemoved(cvm => RemovedCoinViewModels.Add(cvm)) //TODO: fix and test. If I directly unsubscribe from Coin_PropertyChanged then Unspent propchange not triggered in some cases => spent money stays in list
- .Sort(MyComparer, comparerChanged: sortChanged, resetThreshold: 5)
- .Bind(out _coinViewModels)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe().DisposeWith(Disposables);
-
- foreach (var sc in Global.WalletService.Coins.Where(sc => sc.Unspent))
- {
- RootList.Add(new CoinViewModel(sc).DisposeWith(Disposables));
- }
-
- Global.WalletService.Coins.CollectionChanged += Coins_CollectionGlobalChanged;
-
- this.WhenAnyValue(x => x.AmountSortDirection).Subscribe(x =>
- {
- if (x != SortOrder.None)
- {
- PrivacySortDirection = SortOrder.None;
- StatusSortDirection = SortOrder.None;
- HistorySortDirection = SortOrder.None;
- }
- }).DisposeWith(Disposables);
-
- this.WhenAnyValue(x => x.HistorySortDirection).Subscribe(x =>
- {
- if (x != SortOrder.None)
- {
- AmountSortDirection = SortOrder.None;
- StatusSortDirection = SortOrder.None;
- PrivacySortDirection = SortOrder.None;
- }
- }).DisposeWith(Disposables);
-
- this.WhenAnyValue(x => x.StatusSortDirection).Subscribe(x =>
- {
- if (x != SortOrder.None)
- {
- AmountSortDirection = SortOrder.None;
- PrivacySortDirection = SortOrder.None;
- HistorySortDirection = SortOrder.None;
- }
- }).DisposeWith(Disposables);
-
- this.WhenAnyValue(x => x.PrivacySortDirection).Subscribe(x =>
- {
- if (x != SortOrder.None)
- {
- AmountSortDirection = SortOrder.None;
- StatusSortDirection = SortOrder.None;
- HistorySortDirection = SortOrder.None;
- }
- }).DisposeWith(Disposables);
-
EnqueueCoin = ReactiveCommand.Create(() =>
{
if (SelectedCoin is null) return;
//await Global.ChaumianClient.QueueCoinsToMixAsync()
- }).DisposeWith(Disposables);
+ });
DequeueCoin = ReactiveCommand.Create(() =>
{
if (SelectedCoin is null) return;
DequeueCoinsPressed?.Invoke();
- }, this.WhenAnyValue(x => x.CanDeqeue)).DisposeWith(Disposables);
+ }, this.WhenAnyValue(x => x.CanDeqeue));
SelectAllCheckBoxCommand = ReactiveCommand.Create(() =>
{
@@ -278,7 +214,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
SelectAllCheckBoxState = false;
break;
}
- }).DisposeWith(Disposables);
+ });
SelectPrivateCheckBoxCommand = ReactiveCommand.Create(() =>
{
@@ -297,7 +233,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
SelectPrivateCheckBoxState = false;
break;
}
- }).DisposeWith(Disposables);
+ });
SelectNonPrivateCheckBoxCommand = ReactiveCommand.Create(() =>
{
@@ -316,14 +252,118 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
SelectNonPrivateCheckBoxState = false;
break;
}
- }).DisposeWith(Disposables);
+ });
+
+ SortCommand = ReactiveCommand.Create(() => RefreshOrdering());
+
+ RemovedCoinViewModels = new List<CoinViewModel>();
+
+ this.WhenAnyValue(x => x.AmountSortDirection).Subscribe(x =>
+ {
+ if (x != SortOrder.None)
+ {
+ PrivacySortDirection = SortOrder.None;
+ StatusSortDirection = SortOrder.None;
+ HistorySortDirection = SortOrder.None;
+ }
+ });
+
+ this.WhenAnyValue(x => x.HistorySortDirection).Subscribe(x =>
+ {
+ if (x != SortOrder.None)
+ {
+ AmountSortDirection = SortOrder.None;
+ StatusSortDirection = SortOrder.None;
+ PrivacySortDirection = SortOrder.None;
+ }
+ });
+
+ this.WhenAnyValue(x => x.StatusSortDirection).Subscribe(x =>
+ {
+ if (x != SortOrder.None)
+ {
+ AmountSortDirection = SortOrder.None;
+ PrivacySortDirection = SortOrder.None;
+ HistorySortDirection = SortOrder.None;
+ }
+ });
+
+ this.WhenAnyValue(x => x.PrivacySortDirection).Subscribe(x =>
+ {
+ if (x != SortOrder.None)
+ {
+ AmountSortDirection = SortOrder.None;
+ StatusSortDirection = SortOrder.None;
+ HistorySortDirection = SortOrder.None;
+ }
+ });
+
+
+ AmountSortDirection = SortOrder.Decreasing;
+ RefreshOrdering();
+
+ var sortChanged = this.WhenValueChanged(@this => MyComparer).Select(_ => MyComparer);
+
+ RootList = new SourceList<CoinViewModel>();
+ RootList.Connect()
+ .OnItemAdded(cvm => cvm.PropertyChanged += Coin_PropertyChanged)
+ .OnItemRemoved(cvm => RemovedCoinViewModels.Add(cvm)) //TODO: fix and test. If I directly unsubscribe from Coin_PropertyChanged then Unspent propchange not triggered in some cases => spent money stays in list
+ .Sort(MyComparer, comparerChanged: sortChanged, resetThreshold: 5)
+ .Bind(out _coinViewModels)
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe();
+ }
+
+ public void OnOpen()
+ {
+ _disposables = new CompositeDisposable();
+
+
+ foreach (var sc in Global.WalletService.Coins.Where(sc => sc.Unspent))
+ {
+ RootList.Add(new CoinViewModel(sc).DisposeWith(_disposables));
+ }
+
+ Global.WalletService.Coins.CollectionChanged += Coins_CollectionGlobalChanged;
- SortCommand = ReactiveCommand.Create(() => RefreshOrdering()).DisposeWith(Disposables);
SetSelections();
SetCoinJoinStatusWidth();
}
+ public void OnClose()
+ {
+ if (Global.WalletService?.Coins != null)
+ {
+ Global.WalletService.Coins.CollectionChanged -= Coins_CollectionGlobalChanged;
+ }
+
+ if (RootList?.Items != null)
+ {
+ foreach (CoinViewModel cvm in RootList.Items)
+ {
+ if (cvm != null)
+ {
+ cvm.PropertyChanged -= Coin_PropertyChanged;
+ }
+ }
+ }
+
+ if (RemovedCoinViewModels != null)
+ {
+ foreach (var cvm in RemovedCoinViewModels)
+ {
+ if (cvm != null)
+ {
+ cvm.PropertyChanged -= Coin_PropertyChanged;
+ }
+ }
+ }
+
+ RootList.Clear();
+ _disposables?.Dispose();
+ }
+
private void Coins_CollectionGlobalChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Dispatcher.UIThread.PostLogException(() =>
@@ -333,7 +373,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
case NotifyCollectionChangedAction.Add:
foreach (SmartCoin c in e.NewItems.Cast<SmartCoin>().Where(sc => sc.Unspent))
{
- RootList.Add(new CoinViewModel(c).DisposeWith(Disposables));
+ RootList.Add(new CoinViewModel(c).DisposeWith(_disposables));
}
break;
@@ -418,34 +458,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
{
if (disposing)
{
- if (Global.WalletService?.Coins != null)
- {
- Global.WalletService.Coins.CollectionChanged -= Coins_CollectionGlobalChanged;
- }
-
- if (RootList?.Items != null)
- {
- foreach (CoinViewModel cvm in RootList.Items)
- {
- if (cvm != null)
- {
- cvm.PropertyChanged -= Coin_PropertyChanged;
- }
- }
- }
-
- if (RemovedCoinViewModels != null)
- {
- foreach (var cvm in RemovedCoinViewModels)
- {
- if (cvm != null)
- {
- cvm.PropertyChanged -= Coin_PropertyChanged;
- }
- }
- }
- Disposables?.Dispose();
}
_disposedValue = true;

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/HistoryTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/HistoryTabViewModel.cs
@@ -287,5 +287,46 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
}
}
}
+
+ public override bool OnClose()
+ {
+ Dispose();
+
+ return base.OnClose();
+ }
+
+ #region IDisposable Support
+
+ private volatile bool _disposedValue = false; // To detect redundant calls
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ if (Transactions != null)
+ {
+ foreach (var tr in Transactions)
+ {
+ tr?.Dispose();
+ }
+ }
+ Disposables?.Dispose();
+ }
+
+ _transactions = null;
+ _disposedValue = true;
+ }
+ }
+
+ // This code added to correctly implement the disposable pattern.
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
+ Dispose(true);
+ }
+
+ #endregion IDisposable Support
}
}

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
@@ -77,7 +77,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
UsdExchangeRate = Global.Synchronizer.UsdExchangeRate;
SetAmountWatermarkAndToolTip(Money.Zero);
- CoinList = new CoinListViewModel().DisposeWith(Disposables);
+ CoinList = new CoinListViewModel();
BuildTransactionButtonText = BuildTransactionButtonTextString;
@@ -904,32 +904,18 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
public ReactiveCommand FeeRateCommand { get; }
- #region IDisposable Support
-
- protected override void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
+ public override void OnOpen()
{
- if (Global.Synchronizer != null)
- {
- Global.Synchronizer.PropertyChanged -= Synchronizer_PropertyChanged;
- }
+ CoinList.OnOpen();
- if (_coinList != null)
- {
- _coinList.SelectionChanged -= CoinList_SelectionChanged;
- _coinList.DequeueCoinsPressed -= CoinsList_DequeueCoinsPressedAsync;
- }
+ base.OnOpen();
}
- base.Dispose(disposing);
+ public override bool OnClose()
+ {
+ CoinList.OnClose();
- _disposedValue = true;
- }
+ return base.OnClose();
}
-
- #endregion IDisposable Support
}
}

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/WalletActionViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/WalletActionViewModel.cs
@@ -10,7 +10,7 @@ using WalletWasabi.Gui.ViewModels;
namespace WalletWasabi.Gui.Controls.WalletExplorer
{
- public class WalletActionViewModel : WasabiDocumentTabViewModel, IDisposable
+ public class WalletActionViewModel : WasabiDocumentTabViewModel
{
protected CompositeDisposable Disposables { get; }
@@ -31,31 +31,5 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
{
IoC.Get<IShell>().AddOrSelectDocument(this);
}
-
- #region IDisposable Support
-
- protected volatile bool _disposedValue = false; // To detect redundant calls
-
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
- {
- Disposables?.Dispose();
- }
-
- _disposedValue = true;
- }
- }
-
- // This code added to correctly implement the disposable pattern.
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- Dispose(true);
- }
-
- #endregion IDisposable Support
}
}

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/WalletInfoViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/WalletInfoViewModel.cs
@@ -168,10 +168,10 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
base.OnSelected();
}
- public override void Close()
+ public override bool OnClose()
{
ClearSensitiveData(true);
- base.Close();
+ return base.OnClose();
}
private void SetWarningMessage(string message)
@@ -197,24 +197,5 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
}
});
}
-
- #region IDisposable Support
-
- protected override void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
- {
- Closing?.Cancel();
- }
-
- base.Dispose(disposing);
-
- _disposedValue = true;
- }
- }
-
- #endregion IDisposable Support
}
}

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/WalletViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/WalletViewModel.cs
@@ -45,11 +45,11 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
Actions = new ObservableCollection<WalletActionViewModel>
{
- new SendTabViewModel(this).DisposeWith(Disposables),
- new ReceiveTabViewModel(this).DisposeWith(Disposables),
- new CoinJoinTabViewModel(this).DisposeWith(Disposables),
- new HistoryTabViewModel(this).DisposeWith(Disposables),
- new WalletInfoViewModel(this).DisposeWith(Disposables)
+ new SendTabViewModel(this),
+ new ReceiveTabViewModel(this),
+ new CoinJoinTabViewModel(this),
+ new HistoryTabViewModel(this),
+ new WalletInfoViewModel(this)
};
Actions[0].DisplayActionTab();

MODIFY
WalletWasabi.Gui/Program.cs
WalletWasabi.Gui/Program.cs
@@ -63,7 +63,6 @@ namespace WalletWasabi.Gui
}
finally
{
- MainWindowViewModel.Instance?.Dispose();
statusBar?.Dispose();
await Global.DisposeAsync();
AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;

MODIFY
WalletWasabi.Gui/ViewModels/MainWindowViewModel.cs
WalletWasabi.Gui/ViewModels/MainWindowViewModel.cs
@@ -13,7 +13,7 @@ using System.Threading.Tasks;
namespace WalletWasabi.Gui.ViewModels
{
- public class MainWindowViewModel : ViewModelBase, IDisposable
+ public class MainWindowViewModel : ViewModelBase
{
private ModalDialogViewModelBase _modalDialog;
private bool _canClose = true;
@@ -89,37 +89,5 @@ namespace WalletWasabi.Gui.ViewModels
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}
-
- #region IDisposable Support
-
- private volatile bool _disposedValue = false; // To detect redundant calls
-
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposedValue)
- {
- if (disposing)
- {
- if (Shell?.Documents != null)
- {
- foreach (var tab in Shell.Documents.OfType<IDisposable>())
- {
- tab?.Dispose();
- }
- }
- }
-
- _disposedValue = true;
- }
- }
-
- // This code added to correctly implement the disposable pattern.
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- Dispose(true);
- }
-
- #endregion IDisposable Support
}
}

MODIFY
WalletWasabi.Gui/ViewModels/WasabiDocumentTabViewModel.cs
WalletWasabi.Gui/ViewModels/WasabiDocumentTabViewModel.cs
@@ -33,12 +33,6 @@ namespace WalletWasabi.Gui.ViewModels
public bool IsDirty { get; set; }
- public virtual void Close()
- {
- IoC.Get<IShell>().RemoveDocument(this);
- IsSelected = false;
- }
-
public virtual void OnSelected()
{
IsSelected = true;
@@ -49,8 +43,14 @@ namespace WalletWasabi.Gui.ViewModels
IsSelected = false;
}
- public bool OnClose()
+ public virtual void OnOpen ()
{
+
+ }
+
+ public virtual bool OnClose()
+ {
+ IsSelected = false;
IoC.Get<IShell>().RemoveDocument(this);
return true;

clear most of IDisposable infection from ViewModels