Skip to content

Commit 34e5670

Browse files
authored
Merge pull request #2766 from wabbajack-tools/post_compilation_freeze
Fix post compilation freezes
2 parents f9c76cf + a3cbe2b commit 34e5670

File tree

3 files changed

+54
-13
lines changed

3 files changed

+54
-13
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
* Added 2FA support for MEGA login, added some extra logging for MEGA logins
77
* Special thanks to [@erri120](https://www.github.com/erri120) who originally implemented part of this in Wabbajack and the MegaApiClient library 4 years ago, which made the change rather easy
88
* Added a warning for when WebView is not loading
9-
* Add progress indicator to the publish button after compilation (thanks to [@JanuarySnow](https://www.github.com/JanuarySnow)))
9+
* Add progress indicator to the publish button after compilation (thanks to [@JanuarySnow](https://www.github.com/JanuarySnow))
1010
* Improve validation before being able to install, should avoid users installing to important folders/the Wabbajack installation directory
11+
* Adjusted the in-app log viewer to not constantly queue updates but to update it periodically instead to avoid freezes when too many log rows are queued (thanks to [@JanuarySnow](https://www.github.com/JanuarySnow))
1112

1213
#### Version - 4.0.0.3 - 3/20/2025
1314
* Fixed the open logs folder button not actually opening the logs folder on a failed installation

Wabbajack.App.Wpf/Models/LogStream.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,22 @@ public LogStream()
3333
.DisposeWith(_disposables);
3434

3535
Messages
36-
.Subscribe(m =>
36+
.Buffer(TimeSpan.FromMilliseconds(100))
37+
.Where(batch => batch.Count > 0)
38+
.Subscribe(batch =>
3739
{
38-
RxApp.MainThreadScheduler.Schedule(m, (_, message) =>
40+
RxApp.MainThreadScheduler.Schedule(batch, (scheduler, messages) =>
3941
{
40-
_messageLog.AddOrUpdate(message);
42+
_messageLog.Edit(innerCache =>
43+
{
44+
foreach (var message in messages)
45+
innerCache.AddOrUpdate(message);
46+
});
47+
4148
return Disposable.Empty;
4249
});
4350
})
4451
.DisposeWith(_disposables);
45-
46-
_messages.DisposeWith(_disposables);
4752
}
4853

4954
protected override void Dispose(bool disposing)

Wabbajack.App.Wpf/Util/AutoScrollBehavior.cs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,15 @@ private class Capture : IDisposable
8484
{
8585
private readonly INotifyCollectionChanged _incc;
8686
private readonly ListBox _listBox;
87+
private DateTime _lastScrollTime = DateTime.MinValue;
88+
private readonly TimeSpan _throttleInterval = TimeSpan.FromMilliseconds(100);
8789

8890
public Capture(ListBox listBox)
8991
{
90-
this._listBox = listBox;
92+
_listBox = listBox;
9193
_incc = listBox.ItemsSource as INotifyCollectionChanged;
92-
if (_incc != null) _incc.CollectionChanged += incc_CollectionChanged;
94+
if (_incc != null)
95+
_incc.CollectionChanged += incc_CollectionChanged;
9396
}
9497

9598
public void Dispose()
@@ -100,15 +103,47 @@ public void Dispose()
100103

101104
private void incc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
102105
{
103-
if (e.Action == NotifyCollectionChangedAction.Add)
106+
if (e.Action != NotifyCollectionChangedAction.Add || e.NewItems == null || e.NewItems.Count == 0)
107+
return;
108+
109+
// Throttle to avoid layout storms
110+
var now = DateTime.Now;
111+
if (now - _lastScrollTime < _throttleInterval)
112+
return;
113+
114+
_lastScrollTime = now;
115+
116+
// Defer to Dispatcher to ensure layout has completed
117+
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
104118
{
119+
var item = e.NewItems[0];
120+
121+
// Avoid triggering if item is already in view
122+
if (IsItemVisible(_listBox, item))
123+
return;
124+
105125
try
106126
{
107-
_listBox.ScrollIntoView(e.NewItems[0]);
108-
_listBox.SelectedItem = e.NewItems[0];
127+
_listBox.ScrollIntoView(item);
128+
_listBox.SelectedItem = item;
109129
}
110-
catch (ArgumentOutOfRangeException) { }
111-
}
130+
catch (ArgumentOutOfRangeException)
131+
{
132+
// Safe fallback
133+
}
134+
}), System.Windows.Threading.DispatcherPriority.Background);
135+
}
136+
137+
private static bool IsItemVisible(ListBox listBox, object item)
138+
{
139+
var container = listBox.ItemContainerGenerator.ContainerFromItem(item) as FrameworkElement;
140+
if (container == null)
141+
return false;
142+
143+
var bounds = container.TransformToAncestor(listBox)
144+
.TransformBounds(new Rect(0, 0, container.ActualWidth, container.ActualHeight));
145+
var viewport = new Rect(0, 0, listBox.ActualWidth, listBox.ActualHeight);
146+
return viewport.Contains(bounds.TopLeft) || viewport.Contains(bounds.BottomRight);
112147
}
113148
}
114149
}

0 commit comments

Comments
 (0)