mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-23 20:47:25 -08:00
optimize<*>: use custom view locator instead of ContentControl.DataTemplates to avoid memory leak.
This commit is contained in:
parent
27d4dd5f64
commit
60e664ab26
9 changed files with 77 additions and 62 deletions
|
@ -160,26 +160,23 @@ namespace SourceGit.ViewModels {
|
||||||
} else {
|
} else {
|
||||||
page = ActivePage;
|
page = ActivePage;
|
||||||
page.Node = node;
|
page.Node = node;
|
||||||
page.View = new Views.Repository() { DataContext = repo };
|
page.Data = repo;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
page.Node = node;
|
page.Node = node;
|
||||||
page.View = new Views.Repository() { DataContext = repo };
|
page.Data = repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivePage = page;
|
ActivePage = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseRepositoryInTab(LauncherPage page) {
|
private void CloseRepositoryInTab(LauncherPage page) {
|
||||||
if (page.Node.IsRepository) {
|
if (page.Data is Repository repo) {
|
||||||
var repo = Preference.FindRepository(page.Node.Id);
|
Commands.AutoFetch.RemoveRepository(repo.FullPath);
|
||||||
if (repo != null) {
|
repo.Close();
|
||||||
Commands.AutoFetch.RemoveRepository(repo.FullPath);
|
|
||||||
repo.Close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
page.View = null;
|
page.Data = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LauncherPage _activePage = null;
|
private LauncherPage _activePage = null;
|
||||||
|
|
|
@ -8,9 +8,9 @@ namespace SourceGit.ViewModels {
|
||||||
set => SetProperty(ref _node, value);
|
set => SetProperty(ref _node, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object View {
|
public object Data {
|
||||||
get => _view;
|
get => _data;
|
||||||
set => SetProperty(ref _view, value);
|
set => SetProperty(ref _data, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AvaloniaList<Models.Notification> Notifications {
|
public AvaloniaList<Models.Notification> Notifications {
|
||||||
|
@ -25,12 +25,12 @@ namespace SourceGit.ViewModels {
|
||||||
Bookmark = 0,
|
Bookmark = 0,
|
||||||
IsRepository = false,
|
IsRepository = false,
|
||||||
};
|
};
|
||||||
_view = new Views.Welcome() { DataContext = new Welcome() };
|
_data = new Welcome();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LauncherPage(RepositoryNode node, Repository repo) {
|
public LauncherPage(RepositoryNode node, Repository repo) {
|
||||||
_node = node;
|
_node = node;
|
||||||
_view = new Views.Repository() { DataContext = repo };
|
_data = repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetId() {
|
public override string GetId() {
|
||||||
|
@ -48,6 +48,6 @@ namespace SourceGit.ViewModels {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RepositoryNode _node = null;
|
private RepositoryNode _node = null;
|
||||||
private object _view = null;
|
private object _data = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.VisualTree;
|
using Avalonia.VisualTree;
|
||||||
using System;
|
using System;
|
||||||
|
@ -208,11 +207,6 @@ namespace SourceGit.Views {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUnloaded(RoutedEventArgs e) {
|
|
||||||
base.OnUnloaded(e);
|
|
||||||
GC.Collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCommitDataGridLayoutUpdated(object sender, EventArgs e) {
|
private void OnCommitDataGridLayoutUpdated(object sender, EventArgs e) {
|
||||||
commitGraph.InvalidateVisual();
|
commitGraph.InvalidateVisual();
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,8 +223,8 @@
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- Page container -->
|
<!-- Page body -->
|
||||||
<ContentControl Grid.Row="1" Background="{DynamicResource Brush.ToolBar}" Content="{Binding ActivePage.View}"/>
|
<v:LauncherBody Grid.Row="1" Background="{DynamicResource Brush.ToolBar}" Data="{Binding ActivePage.Data}"/>
|
||||||
|
|
||||||
<!-- Popup container -->
|
<!-- Popup container -->
|
||||||
<Grid Grid.Row="1" x:Name="popupContainer" Margin="0,36,0,0" ClipToBounds="True" IsVisible="{Binding ActivePage.Popup, Converter={x:Static ObjectConverters.IsNotNull}}">
|
<Grid Grid.Row="1" x:Name="popupContainer" Margin="0,36,0,0" ClipToBounds="True" IsVisible="{Binding ActivePage.Popup, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
|
|
@ -23,6 +23,34 @@ namespace SourceGit.Views {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class LauncherBody : Border {
|
||||||
|
public static readonly StyledProperty<object> DataProperty =
|
||||||
|
AvaloniaProperty.Register<LauncherBody, object>(nameof(Data), false);
|
||||||
|
|
||||||
|
public object Data {
|
||||||
|
get => GetValue(DataProperty);
|
||||||
|
set => SetValue(DataProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Type StyleKeyOverride => typeof(Border);
|
||||||
|
|
||||||
|
static LauncherBody() {
|
||||||
|
DataProperty.Changed.AddClassHandler<LauncherBody>((body, ev) => {
|
||||||
|
var data = body.Data;
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
body.Child = null;
|
||||||
|
} else if (data is ViewModels.Welcome) {
|
||||||
|
body.Child = new Welcome { DataContext = data };
|
||||||
|
} else if (data is ViewModels.Repository) {
|
||||||
|
body.Child = new Repository { DataContext = data };
|
||||||
|
} else {
|
||||||
|
body.Child = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public partial class Launcher : Window, Models.INotificationReceiver {
|
public partial class Launcher : Window, Models.INotificationReceiver {
|
||||||
public Launcher() {
|
public Launcher() {
|
||||||
DataContext = new ViewModels.Launcher();
|
DataContext = new ViewModels.Launcher();
|
||||||
|
|
|
@ -447,25 +447,7 @@
|
||||||
<Button Grid.Column="3" Classes="flat" FontWeight="Regular" Content="{DynamicResource Text.Repository.Abort}" Height="20" Padding="8,0" Margin="4,0" Command="{Binding AbortMerge}"/>
|
<Button Grid.Column="3" Classes="flat" FontWeight="Regular" Content="{DynamicResource Text.Repository.Abort}" Height="20" Padding="8,0" Margin="4,0" Command="{Binding AbortMerge}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<ContentControl Grid.Row="1" Content="{Binding SelectedView}">
|
<v:RepositorySubView Grid.Row="1" Data="{Binding SelectedView}"/>
|
||||||
<ContentControl.DataTemplates>
|
|
||||||
<DataTemplate DataType="vm:Histories">
|
|
||||||
<v:Histories/>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<DataTemplate DataType="vm:WorkingCopy">
|
|
||||||
<v:WorkingCopy/>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<DataTemplate DataType="vm:StashesPage">
|
|
||||||
<v:StashesPage/>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<DataTemplate DataType="x:Double">
|
|
||||||
<Border/>
|
|
||||||
</DataTemplate>
|
|
||||||
</ContentControl.DataTemplates>
|
|
||||||
</ContentControl>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -1,11 +1,45 @@
|
||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using SourceGit.ViewModels;
|
using SourceGit.ViewModels;
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SourceGit.Views {
|
namespace SourceGit.Views {
|
||||||
|
public class RepositorySubView : Border {
|
||||||
|
public static readonly StyledProperty<object> DataProperty =
|
||||||
|
AvaloniaProperty.Register<RepositorySubView, object>(nameof(Data), false);
|
||||||
|
|
||||||
|
public object Data {
|
||||||
|
get => GetValue(DataProperty);
|
||||||
|
set => SetValue(DataProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Type StyleKeyOverride => typeof(Border);
|
||||||
|
|
||||||
|
static RepositorySubView() {
|
||||||
|
DataProperty.Changed.AddClassHandler<RepositorySubView>((view, ev) => {
|
||||||
|
var data = view.Data;
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
view.Child = null;
|
||||||
|
} else if (data is ViewModels.Histories) {
|
||||||
|
view.Child = new Histories { DataContext = data };
|
||||||
|
} else if (data is ViewModels.WorkingCopy) {
|
||||||
|
view.Child = new WorkingCopy { DataContext = data };
|
||||||
|
} else if (data is ViewModels.StashesPage) {
|
||||||
|
view.Child = new StashesPage { DataContext = data };
|
||||||
|
} else {
|
||||||
|
view.Child = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public partial class Repository : UserControl {
|
public partial class Repository : UserControl {
|
||||||
public Repository() {
|
public Repository() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
|
@ -1,16 +1,9 @@
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace SourceGit.Views {
|
namespace SourceGit.Views {
|
||||||
public partial class StashesPage : UserControl {
|
public partial class StashesPage : UserControl {
|
||||||
public StashesPage() {
|
public StashesPage() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUnloaded(RoutedEventArgs e) {
|
|
||||||
base.OnUnloaded(e);
|
|
||||||
GC.Collect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.VisualTree;
|
using Avalonia.VisualTree;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace SourceGit.Views {
|
namespace SourceGit.Views {
|
||||||
|
@ -11,18 +10,6 @@ namespace SourceGit.Views {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUnloaded(RoutedEventArgs e) {
|
|
||||||
var vm = DataContext as ViewModels.WorkingCopy;
|
|
||||||
vm.SelectedStagedChange = null;
|
|
||||||
vm.SelectedStagedTreeNode = null;
|
|
||||||
vm.SelectedUnstagedChange = null;
|
|
||||||
vm.SelectedUnstagedTreeNode = null;
|
|
||||||
vm.SetDetail(null, false);
|
|
||||||
|
|
||||||
base.OnUnloaded(e);
|
|
||||||
GC.Collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ViewAssumeUnchanged(object sender, RoutedEventArgs e) {
|
private void ViewAssumeUnchanged(object sender, RoutedEventArgs e) {
|
||||||
var repoPage = this.FindAncestorOfType<Repository>();
|
var repoPage = this.FindAncestorOfType<Repository>();
|
||||||
if (repoPage != null) {
|
if (repoPage != null) {
|
||||||
|
|
Loading…
Reference in a new issue