fix some memory leaks with interaction between coinlist and coinview model
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
@@ -199,13 +199,6 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe();
- foreach (var sc in Global.WalletService.Coins.Where(sc => sc.Unspent && !sc.IsDust))
- {
- RootList.Add(new CoinViewModel(sc));
- }
-
- Global.WalletService.Coins.CollectionChanged += Coins_CollectionGlobalChanged;
-
this.WhenAnyValue(x => x.AmountSortDirection).Subscribe(x =>
{
if (x != SortOrder.None)
@@ -354,7 +347,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
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
+ .OnItemRemoved(cvm => cvm.PropertyChanged -= Coin_PropertyChanged) //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)
@@ -365,10 +358,9 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
{
_disposables = new CompositeDisposable();
-
foreach (var sc in Global.WalletService.Coins.Where(sc => sc.Unspent))
{
- RootList.Add(new CoinViewModel(sc));
+ RootList.Add(new CoinViewModel(sc).DisposeWith(_disposables));
}
Global.WalletService.Coins.CollectionChanged += Coins_CollectionGlobalChanged;

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinViewModel.cs
@@ -12,19 +12,16 @@ using WalletWasabi.Models.ChaumianCoinJoin;
namespace WalletWasabi.Gui.Controls.WalletExplorer
{
- public class CoinViewModel : ViewModelBase
+ public class CoinViewModel : ViewModelBase, IDisposable
{
- private CompositeDisposable Disposables { get; }
+ private CompositeDisposable _disposables;
private bool _isSelected;
private SmartCoinStatus _smartCoinStatus;
public CoinViewModel(SmartCoin model)
{
- throw new Exception("TODO");
- // copy values from model to viewmodel so we dont hold a reference?
-
- Disposables = new CompositeDisposable();
+ _disposables = new CompositeDisposable();
Model = model;
@@ -32,58 +29,60 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
{
RefreshSmartCoinStatus();
this.RaisePropertyChanged(nameof(Confirmed));
- });
+ }).DisposeWith(_disposables);
model.WhenAnyValue(x => x.Unavailable).ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ =>
{
this.RaisePropertyChanged(nameof(Unavailable));
- });
+ }).DisposeWith(_disposables);
model.WhenAnyValue(x => x.CoinJoinInProgress).ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ =>
{
RefreshSmartCoinStatus();
this.RaisePropertyChanged(nameof(CoinJoinInProgress));
- });
+ }).DisposeWith(_disposables);
model.WhenAnyValue(x => x.IsBanned).ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ =>
{
RefreshSmartCoinStatus();
- });
+ }).DisposeWith(_disposables);
model.WhenAnyValue(x => x.SpentAccordingToBackend).ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ =>
{
RefreshSmartCoinStatus();
- });
+ }).DisposeWith(_disposables);
model.WhenAnyValue(x => x.Unspent).ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ =>
{
this.RaisePropertyChanged(nameof(Unspent));
- });
+ }).DisposeWith(_disposables);
model.WhenAnyValue(x => x.Clusters).ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ =>
{
this.RaisePropertyChanged(nameof(Clusters));
- });
+ }).DisposeWith(_disposables);
this.WhenAnyValue(x => x.Status).Subscribe(_ =>
{
this.RaisePropertyChanged(nameof(ToolTip));
- });
+ }).DisposeWith(_disposables);
- // TODO This will need disposing.
- Global.Synchronizer.WhenAnyValue(x => x.BestBlockchainHeight).ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ =>
+ Global.Synchronizer.WhenAnyValue(x => x.BestBlockchainHeight)
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(_ =>
{
RefreshSmartCoinStatus();
this.RaisePropertyChanged(nameof(Confirmations));
- }).DisposeWith(Disposables);
-
- // TODO this can be observable too.
- Global.ChaumianClient.StateUpdated += ChaumianClient_StateUpdated;
- }
+ }).DisposeWith(_disposables);
- private void ChaumianClient_StateUpdated(object sender, EventArgs e)
+ Observable.FromEventPattern(
+ Global.ChaumianClient,
+ nameof(Global.ChaumianClient.StateUpdated),
+ RxApp.MainThreadScheduler)
+ .Subscribe(_ =>
{
RefreshSmartCoinStatus();
+ }).DisposeWith(_disposables);
}
public SmartCoin Model { get; }
@@ -157,6 +156,12 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
set => this.RaiseAndSetIfChanged(ref _smartCoinStatus, value);
}
+ public void Dispose()
+ {
+ _disposables?.Dispose();
+ _disposables = null;
+ }
+
private void RefreshSmartCoinStatus()
{
Status = GetSmartCoinStatus();

fix some memory leaks with interaction between coinlist and coinview model