Browse Source

Make the main menu extensible using MEF.

pull/70/head
Daniel Grunwald 15 years ago
parent
commit
fe8f32bef0
  1. 13
      ILSpy/AboutPage.cs
  2. 24
      ILSpy/Commands.cs
  3. 30
      ILSpy/ExportCommandAttribute.cs
  4. 11
      ILSpy/MainWindow.xaml
  5. 79
      ILSpy/MainWindow.xaml.cs
  6. 5
      ILSpy/TextView/DecompilerTextView.cs

13
ILSpy/AboutPage.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
@ -14,13 +15,23 @@ using System.Windows.Data; @@ -14,13 +15,23 @@ using System.Windows.Data;
using System.Windows.Input;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
namespace ICSharpCode.ILSpy
{
static class AboutPage
[ExportMainMenuCommand(Menu = "_Help", Header = "_About", Order = 99999)]
sealed class AboutPage : SimpleCommand
{
[Import]
DecompilerTextView decompilerTextView = null;
public override void Execute(object parameter)
{
Display(decompilerTextView);
}
static readonly Uri UpdateUrl = new Uri("http://www.ilspy.net/updates.xml");
static AvailableVersionInfo latestAvailableVersion;

24
ILSpy/Commands.cs

@ -6,6 +6,15 @@ using System.Windows.Input; @@ -6,6 +6,15 @@ using System.Windows.Input;
namespace ICSharpCode.ILSpy
{
[ExportMainMenuCommand(Menu = "_File", Header = "E_xit", Order = 99999, Category = "Exit")]
sealed class ExitCommand : SimpleCommand
{
public override void Execute(object parameter)
{
MainWindow.Instance.Close();
}
}
[ExportToolbarCommand(ToolTip = "Back", Icon = "Images/Back.png", Category = "Navigation")]
sealed class BrowseBackCommand : CommandWrapper {
public BrowseBackCommand() : base(NavigationCommands.BrowseBack) {}
@ -50,4 +59,19 @@ namespace ICSharpCode.ILSpy @@ -50,4 +59,19 @@ namespace ICSharpCode.ILSpy
return wrappedCommand.CanExecute(parameter);
}
}
public abstract class SimpleCommand : ICommand
{
public event EventHandler CanExecuteChanged {
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public abstract void Execute(object parameter);
public virtual bool CanExecute(object parameter)
{
return true;
}
}
}

30
ILSpy/ExportCommandAttribute.cs

@ -22,7 +22,7 @@ namespace ICSharpCode.ILSpy @@ -22,7 +22,7 @@ namespace ICSharpCode.ILSpy
public class ExportToolbarCommandAttribute : ExportAttribute
{
public ExportToolbarCommandAttribute()
: base(typeof(ICommand))
: base("ToolbarCommand", typeof(ICommand))
{
}
@ -32,4 +32,32 @@ namespace ICSharpCode.ILSpy @@ -32,4 +32,32 @@ namespace ICSharpCode.ILSpy
public double Order { get; set; }
}
#endregion
#region Main Menu
public interface IMainMenuCommandMetadata
{
string Icon { get; }
string Header { get; }
string Menu { get; }
string Category { get; }
double Order { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class ExportMainMenuCommandAttribute : ExportAttribute
{
public ExportMainMenuCommandAttribute()
: base("MainMenuCommand", typeof(ICommand))
{
}
public string Icon { get; set; }
public string Header { get; set; }
public string Menu { get; set; }
public string Category { get; set; }
public double Order { get; set; }
}
#endregion
}

11
ILSpy/MainWindow.xaml

@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
</Window.CommandBindings>
<DockPanel>
<!-- Main menu -->
<Menu DockPanel.Dock="Top">
<Menu DockPanel.Dock="Top" Name="mainMenu">
<MenuItem Header="_File">
<MenuItem Command="Open">
<MenuItem.Icon>
@ -52,8 +52,6 @@ @@ -52,8 +52,6 @@
<Image Width="16" Height="16" Source="Images/SaveFile.png" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="E_xit" Click="ExitClick" />
</MenuItem>
<MenuItem Header="_View">
<MenuItem Header="Show _internal types and members" IsCheckable="True" IsChecked="{Binding FilterSettings.ShowInternalApi}">
@ -63,9 +61,6 @@ @@ -63,9 +61,6 @@
</MenuItem>
<MenuItem Header="Show _analyzer" Name="showAnalyzer" IsCheckable="True" Checked="ShowAnalyzer_Checked" Unchecked="ShowAnalyzer_Unchecked" />
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About" Click="AboutClick" />
</MenuItem>
</Menu>
<!-- ToolBar -->
<ToolBar
@ -135,7 +130,7 @@ @@ -135,7 +130,7 @@
VerticalAlignment="Stretch"
BorderBrush="Transparent" />
<!-- Right pane: Text Editor -->
<Grid Grid.Column="2">
<Grid Grid.Column="2" Name="rightPane">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="*" />
@ -156,7 +151,7 @@ @@ -156,7 +151,7 @@
</DockPanel>
</Border>
<textView:DecompilerTextView x:Name="decompilerTextView" Grid.Row="1" />
<!-- decompilerTextView is inserted into row 1 by code -->
<GridSplitter
Grid.ZIndex="1"

79
ILSpy/MainWindow.xaml.cs

@ -29,8 +29,10 @@ using System.Windows; @@ -29,8 +29,10 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.TreeNodes.Analyzer;
using ICSharpCode.TreeView;
@ -51,6 +53,9 @@ namespace ICSharpCode.ILSpy @@ -51,6 +53,9 @@ namespace ICSharpCode.ILSpy
AssemblyList assemblyList;
AssemblyListTreeNode assemblyListTreeNode;
[Import]
DecompilerTextView decompilerTextView = null;
static MainWindow instance;
public static MainWindow Instance {
@ -78,7 +83,9 @@ namespace ICSharpCode.ILSpy @@ -78,7 +83,9 @@ namespace ICSharpCode.ILSpy
this.WindowState = sessionSettings.WindowState;
InitializeComponent();
decompilerTextView.mainWindow = this;
App.CompositionContainer.ComposeParts(this);
Grid.SetRow(decompilerTextView, 1);
rightPane.Children.Add(decompilerTextView);
if (sessionSettings.SplitterPosition > 0 && sessionSettings.SplitterPosition < 1) {
leftColumn.Width = new GridLength(sessionSettings.SplitterPosition, GridUnitType.Star);
@ -86,28 +93,38 @@ namespace ICSharpCode.ILSpy @@ -86,28 +93,38 @@ namespace ICSharpCode.ILSpy
}
sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged;
App.CompositionContainer.ComposeParts(this);
InitMainMenu();
InitToolbar();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
#region Toolbar extensibility
[ImportMany("ToolbarCommand", typeof(ICommand))]
Lazy<ICommand, IToolbarCommandMetadata>[] toolbarCommands = null;
void InitToolbar()
{
int navigationPos = 0;
int openPos = 1;
foreach (var commandGroup in ToolbarCommands.GroupBy(c => c.Metadata.Category)) {
foreach (var commandGroup in toolbarCommands.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.Category)) {
if (commandGroup.Key == "Navigation") {
foreach (var command in commandGroup.OrderBy(c => c.Metadata.Order)) {
foreach (var command in commandGroup) {
toolBar.Items.Insert(navigationPos++, MakeToolbarItem(command));
openPos++;
}
} else if (commandGroup.Key == "Open") {
foreach (var command in commandGroup.OrderBy(c => c.Metadata.Order)) {
foreach (var command in commandGroup) {
toolBar.Items.Insert(openPos++, MakeToolbarItem(command));
}
} else {
toolBar.Items.Add(new Separator());
foreach (var command in commandGroup.OrderBy(c => c.Metadata.Order)) {
foreach (var command in commandGroup) {
toolBar.Items.Add(MakeToolbarItem(command));
}
}
}
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
Button MakeToolbarItem(Lazy<ICommand, IToolbarCommandMetadata> command)
@ -122,9 +139,41 @@ namespace ICSharpCode.ILSpy @@ -122,9 +139,41 @@ namespace ICSharpCode.ILSpy
}
};
}
#endregion
[ImportMany]
internal Lazy<ICommand, IToolbarCommandMetadata>[] ToolbarCommands { get; set; }
#region Main Menu extensibility
[ImportMany("MainMenuCommand", typeof(ICommand))]
Lazy<ICommand, IMainMenuCommandMetadata>[] mainMenuCommands = null;
void InitMainMenu()
{
foreach (var topLevelMenu in mainMenuCommands.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.Menu)) {
var topLevelMenuItem = mainMenu.Items.OfType<MenuItem>().FirstOrDefault(m => (m.Header as string) == topLevelMenu.Key);
foreach (var category in topLevelMenu.GroupBy(c => c.Metadata.Category)) {
if (topLevelMenuItem == null) {
topLevelMenuItem = new MenuItem();
topLevelMenuItem.Header = topLevelMenu.Key;
mainMenu.Items.Add(topLevelMenuItem);
} else {
topLevelMenuItem.Items.Add(new Separator());
}
foreach (var entry in category) {
MenuItem menuItem = new MenuItem();
menuItem.Header = entry.Metadata.Header;
menuItem.Command = entry.Value;
if (!string.IsNullOrEmpty(entry.Metadata.Icon)) {
menuItem.Icon = new Image {
Width = 16,
Height = 16,
Source = Images.LoadImage(entry.Value, entry.Metadata.Icon)
};
}
topLevelMenuItem.Items.Add(menuItem);
}
}
}
}
#endregion
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
@ -375,18 +424,6 @@ namespace ICSharpCode.ILSpy @@ -375,18 +424,6 @@ namespace ICSharpCode.ILSpy
}
#endregion
#region Exit/About
void ExitClick(object sender, RoutedEventArgs e)
{
Close();
}
void AboutClick(object sender, RoutedEventArgs e)
{
AboutPage.Display(decompilerTextView);
}
#endregion
#region Decompile / Save
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

5
ILSpy/TextView/DecompilerTextView.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@ -49,12 +50,12 @@ namespace ICSharpCode.ILSpy.TextView @@ -49,12 +50,12 @@ namespace ICSharpCode.ILSpy.TextView
/// Manages the TextEditor showing the decompiled code.
/// Contains all the threading logic that makes the decompiler work in the background.
/// </summary>
[Export, PartCreationPolicy(CreationPolicy.Shared)]
public sealed partial class DecompilerTextView : UserControl
{
readonly ReferenceElementGenerator referenceElementGenerator;
readonly UIElementGenerator uiElementGenerator;
FoldingManager foldingManager;
internal MainWindow mainWindow;
DefinitionLookup definitionLookup;
CancellationTokenSource currentCancellationTokenSource;
@ -477,7 +478,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -477,7 +478,7 @@ namespace ICSharpCode.ILSpy.TextView
return;
}
}
mainWindow.JumpToReference(reference);
MainWindow.Instance.JumpToReference(reference);
}
/// <summary>

Loading…
Cancel
Save