有没有办法遍历visual studioshell?
Is there a way to traverse through the visual studio shell?
有没有办法遍历所有 visual studio wpf 元素?我试图了解如何呈现选项卡以在 visual studio 扩展的上下文中添加额外的按钮 + 上下文菜单条目。
是的,我知道 Tab Studios 的存在。如果这不起作用,我不妨尝试一下是否满足我的需求。但在这一点上,我只是好奇如何做到这一点。
这是我到目前为止尝试过的方法:
internal class EditorMargin1 : StackPanel, IWpfTextViewMargin
{
/// <summary>
/// Margin name.
/// </summary>
public const string MarginName = "EditorMargin1";
/// <summary>
/// A value indicating whether the object is disposed.
/// </summary>
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="EditorMargin1"/> class for a given <paramref name="textView"/>.
/// </summary>
/// <param name="textView">The <see cref="IWpfTextView"/> to attach the margin to.</param>
public EditorMargin1(IWpfTextView textView)
{
this.ClipToBounds = true;
var parents = GetParentsRecursive(textView);
var start = 60;
var white = new SolidColorBrush(Color.FromRgb((byte)255, (byte)255, (byte)255));
white.Freeze();
foreach (var parentElement in parents)
{
start += 20;
var background = new SolidColorBrush(Color.FromRgb((byte)start, (byte)0, (byte)start));
var changedColor = false;
var colorableControl = parentElement as Control;
if (colorableControl != null)
{
colorableControl.Background = background;
changedColor = true;
}
this.Children.Add(new Label()
{
Foreground = white,
Background = background,
Content = "Hello EditorMargin1 " + parentElement.GetType().FullName + " has changed color " + changedColor,
});
}
}
private IEnumerable<DependencyObject> GetParentsRecursive(IWpfTextView textView)
{
var control = textView as DependencyObject;
while (control != null)
{
yield return control;
control = LogicalTreeHelper.GetParent(control);
}
}
#region IWpfTextViewMargin
/// <summary>
/// Gets the <see FrameworkElementlement"/> that implements the visual representation of the margin.
/// </summary>
/// <exception cref="ObjectDisposedException">The margin is disposed.</exception>
public FrameworkElement VisualElement
{
// Since this margin implements Canvas, this is the object which renders
// the margin.
get
{
this.ThrowIfDisposed();
return this;
}
}
#endregion
#region ITextViewMargin
/// <summary>
/// Gets the size of the margin.
/// </summary>
/// <remarks>
/// For a horizontal margin this is the height of the margin,
/// since the width will be determined by the <see cref="ITextView"/>.
/// For a vertical margin this is the width of the margin,
/// since the height will be determined by the <see cref="ITextView"/>.
/// </remarks>
/// <exception cref="ObjectDisposedException">The margin is disposed.</exception>
public double MarginSize
{
get
{
this.ThrowIfDisposed();
// Since this is a horizontal margin, its width will be bound to the width of the text view.
// Therefore, its size is its height.
return this.ActualHeight;
}
}
/// <summary>
/// Gets a value indicating whether the margin is enabled.
/// </summary>
/// <exception cref="ObjectDisposedException">The margin is disposed.</exception>
public bool Enabled
{
get
{
this.ThrowIfDisposed();
// The margin should always be enabled
return true;
}
}
/// <summary>
/// Gets the <see cref="ITextViewMargin"/> with the given <paramref name="marginName"/> or null if no match is found
/// </summary>
/// <param name="marginName">The name of the <see cref="ITextViewMargin"/></param>
/// <returns>The <see cref="ITextViewMargin"/> named <paramref name="marginName"/>, or null if no match is found.</returns>
/// <remarks>
/// A margin returns itself if it is passed its own name. If the name does not match and it is a container margin, it
/// forwards the call to its children. Margin name comparisons are case-insensitive.
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="marginName"/> is null.</exception>
public ITextViewMargin GetTextViewMargin(string marginName)
{
return string.Equals(marginName, EditorMargin1.MarginName, StringComparison.OrdinalIgnoreCase) ? this : null;
}
/// <summary>
/// Disposes an instance of <see cref="EditorMargin1"/> class.
/// </summary>
public void Dispose()
{
if (!this.isDisposed)
{
GC.SuppressFinalize(this);
this.isDisposed = true;
}
}
#endregion
/// <summary>
/// Checks and throws <see cref="ObjectDisposedException"/> if the object is disposed.
/// </summary>
private void ThrowIfDisposed()
{
if (this.isDisposed)
{
throw new ObjectDisposedException(MarginName);
}
}
}
/// <summary>
/// Export a <see cref="IWpfTextViewMarginProvider"/>, which returns an instance of the margin for the editor to use.
/// </summary>
[Export(typeof(IWpfTextViewMarginProvider))]
[Name(EditorMargin1.MarginName)]
// [Order(After = PredefinedMarginNames.HorizontalScrollBar)] // Ensure that the margin occurs below the horizontal scrollbar
[MarginContainer(PredefinedMarginNames.Top)] // Set the container to the bottom of the editor window
[ContentType("text")] // Show this margin for all text-based types
[TextViewRole(PredefinedTextViewRoles.Interactive)]
internal sealed class EditorMargin1Factory : IWpfTextViewMarginProvider
{
#region IWpfTextViewMarginProvider
/// <summary>
/// Creates an <see cref="IWpfTextViewMargin"/> for the given <see cref="IWpfTextViewHost"/>.
/// </summary>
/// <param name="wpfTextViewHost">The <see cref="IWpfTextViewHost"/> for which to create the <see cref="IWpfTextViewMargin"/>.</param>
/// <param name="marginContainer">The margin that will contain the newly-created margin.</param>
/// <returns>The <see cref="IWpfTextViewMargin"/>.
/// The value may be null if this <see cref="IWpfTextViewMarginProvider"/> does not participate for this context.
/// </returns>
public IWpfTextViewMargin CreateMargin(IWpfTextViewHost wpfTextViewHost, IWpfTextViewMargin marginContainer)
{
return new EditorMargin1(wpfTextViewHost.TextView);
}
#endregion
}
我 运行 遇到的问题是,从遍历的角度来看,我无法通过 WpfTextViewHost。
有人知道以简单的方式遍历 window 的方法吗?
要遍历所有 Visual Studio wpf 元素,您可以从 System.Windows.Application.Current.MainWindow 开始并使用 System.Windows.Media.VisualTreeHelper.GetChild递归。请参阅以下示例代码 Hide title bar in Visual Studio 2013.
有没有办法遍历所有 visual studio wpf 元素?我试图了解如何呈现选项卡以在 visual studio 扩展的上下文中添加额外的按钮 + 上下文菜单条目。
是的,我知道 Tab Studios 的存在。如果这不起作用,我不妨尝试一下是否满足我的需求。但在这一点上,我只是好奇如何做到这一点。
这是我到目前为止尝试过的方法:
internal class EditorMargin1 : StackPanel, IWpfTextViewMargin
{
/// <summary>
/// Margin name.
/// </summary>
public const string MarginName = "EditorMargin1";
/// <summary>
/// A value indicating whether the object is disposed.
/// </summary>
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="EditorMargin1"/> class for a given <paramref name="textView"/>.
/// </summary>
/// <param name="textView">The <see cref="IWpfTextView"/> to attach the margin to.</param>
public EditorMargin1(IWpfTextView textView)
{
this.ClipToBounds = true;
var parents = GetParentsRecursive(textView);
var start = 60;
var white = new SolidColorBrush(Color.FromRgb((byte)255, (byte)255, (byte)255));
white.Freeze();
foreach (var parentElement in parents)
{
start += 20;
var background = new SolidColorBrush(Color.FromRgb((byte)start, (byte)0, (byte)start));
var changedColor = false;
var colorableControl = parentElement as Control;
if (colorableControl != null)
{
colorableControl.Background = background;
changedColor = true;
}
this.Children.Add(new Label()
{
Foreground = white,
Background = background,
Content = "Hello EditorMargin1 " + parentElement.GetType().FullName + " has changed color " + changedColor,
});
}
}
private IEnumerable<DependencyObject> GetParentsRecursive(IWpfTextView textView)
{
var control = textView as DependencyObject;
while (control != null)
{
yield return control;
control = LogicalTreeHelper.GetParent(control);
}
}
#region IWpfTextViewMargin
/// <summary>
/// Gets the <see FrameworkElementlement"/> that implements the visual representation of the margin.
/// </summary>
/// <exception cref="ObjectDisposedException">The margin is disposed.</exception>
public FrameworkElement VisualElement
{
// Since this margin implements Canvas, this is the object which renders
// the margin.
get
{
this.ThrowIfDisposed();
return this;
}
}
#endregion
#region ITextViewMargin
/// <summary>
/// Gets the size of the margin.
/// </summary>
/// <remarks>
/// For a horizontal margin this is the height of the margin,
/// since the width will be determined by the <see cref="ITextView"/>.
/// For a vertical margin this is the width of the margin,
/// since the height will be determined by the <see cref="ITextView"/>.
/// </remarks>
/// <exception cref="ObjectDisposedException">The margin is disposed.</exception>
public double MarginSize
{
get
{
this.ThrowIfDisposed();
// Since this is a horizontal margin, its width will be bound to the width of the text view.
// Therefore, its size is its height.
return this.ActualHeight;
}
}
/// <summary>
/// Gets a value indicating whether the margin is enabled.
/// </summary>
/// <exception cref="ObjectDisposedException">The margin is disposed.</exception>
public bool Enabled
{
get
{
this.ThrowIfDisposed();
// The margin should always be enabled
return true;
}
}
/// <summary>
/// Gets the <see cref="ITextViewMargin"/> with the given <paramref name="marginName"/> or null if no match is found
/// </summary>
/// <param name="marginName">The name of the <see cref="ITextViewMargin"/></param>
/// <returns>The <see cref="ITextViewMargin"/> named <paramref name="marginName"/>, or null if no match is found.</returns>
/// <remarks>
/// A margin returns itself if it is passed its own name. If the name does not match and it is a container margin, it
/// forwards the call to its children. Margin name comparisons are case-insensitive.
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="marginName"/> is null.</exception>
public ITextViewMargin GetTextViewMargin(string marginName)
{
return string.Equals(marginName, EditorMargin1.MarginName, StringComparison.OrdinalIgnoreCase) ? this : null;
}
/// <summary>
/// Disposes an instance of <see cref="EditorMargin1"/> class.
/// </summary>
public void Dispose()
{
if (!this.isDisposed)
{
GC.SuppressFinalize(this);
this.isDisposed = true;
}
}
#endregion
/// <summary>
/// Checks and throws <see cref="ObjectDisposedException"/> if the object is disposed.
/// </summary>
private void ThrowIfDisposed()
{
if (this.isDisposed)
{
throw new ObjectDisposedException(MarginName);
}
}
}
/// <summary>
/// Export a <see cref="IWpfTextViewMarginProvider"/>, which returns an instance of the margin for the editor to use.
/// </summary>
[Export(typeof(IWpfTextViewMarginProvider))]
[Name(EditorMargin1.MarginName)]
// [Order(After = PredefinedMarginNames.HorizontalScrollBar)] // Ensure that the margin occurs below the horizontal scrollbar
[MarginContainer(PredefinedMarginNames.Top)] // Set the container to the bottom of the editor window
[ContentType("text")] // Show this margin for all text-based types
[TextViewRole(PredefinedTextViewRoles.Interactive)]
internal sealed class EditorMargin1Factory : IWpfTextViewMarginProvider
{
#region IWpfTextViewMarginProvider
/// <summary>
/// Creates an <see cref="IWpfTextViewMargin"/> for the given <see cref="IWpfTextViewHost"/>.
/// </summary>
/// <param name="wpfTextViewHost">The <see cref="IWpfTextViewHost"/> for which to create the <see cref="IWpfTextViewMargin"/>.</param>
/// <param name="marginContainer">The margin that will contain the newly-created margin.</param>
/// <returns>The <see cref="IWpfTextViewMargin"/>.
/// The value may be null if this <see cref="IWpfTextViewMarginProvider"/> does not participate for this context.
/// </returns>
public IWpfTextViewMargin CreateMargin(IWpfTextViewHost wpfTextViewHost, IWpfTextViewMargin marginContainer)
{
return new EditorMargin1(wpfTextViewHost.TextView);
}
#endregion
}
我 运行 遇到的问题是,从遍历的角度来看,我无法通过 WpfTextViewHost。
有人知道以简单的方式遍历 window 的方法吗?
要遍历所有 Visual Studio wpf 元素,您可以从 System.Windows.Application.Current.MainWindow 开始并使用 System.Windows.Media.VisualTreeHelper.GetChild递归。请参阅以下示例代码 Hide title bar in Visual Studio 2013.