-
Notifications
You must be signed in to change notification settings - Fork 59
Closed
Description
Hi!
I'm making an extension that smoothly scrolls a text view and records video (now gif animation).
But there is one problem, line numbers are not repainted when scrolling.
The text is scrolled, but line numbers are frozen.
Please tell me how I can solve this problem?
[VisualStudioContribution]
internal class TakeSnapshotCommand : Microsoft.VisualStudio.Extensibility.Commands.Command {
private TraceSource Logger { get; }
private AsyncServiceProviderInjection<DTE, DTE2> DTE { get; }
private MefInjection<IVsEditorAdaptersFactoryService> EditorAdaptersFactoryService { get; }
private AsyncServiceProviderInjection<SVsTextManager, IVsTextManager> TextManager { get; }
public override CommandConfiguration CommandConfiguration => new CommandConfiguration( "%Snapshot.Pro.TakeSnapshotCommand.DisplayName%" ) {
Icon = new CommandIconConfiguration( ImageMoniker.KnownValues.Extension, IconSettings.IconAndText ),
Placements = [ CommandPlacement.KnownPlacements.ToolsMenu ],
};
public TakeSnapshotCommand(
VisualStudioExtensibility extensibility,
TraceSource logger,
AsyncServiceProviderInjection<DTE, DTE2> dte,
MefInjection<IVsEditorAdaptersFactoryService> editorAdaptersFactoryService,
AsyncServiceProviderInjection<SVsTextManager, IVsTextManager> textManager
) : base( extensibility ) {
Logger = logger;
DTE = dte;
EditorAdaptersFactoryService = editorAdaptersFactoryService;
TextManager = textManager;
}
public override Task InitializeAsync(CancellationToken cancellationToken) {
return base.InitializeAsync( cancellationToken );
}
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) {
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
try {
var textViewSnapshot = await context.GetActiveTextViewAsync( cancellationToken ) ?? throw new NullReferenceException( "ITextViewSnapshot is null" );
//var textDocumentSnapshot = view.Document ?? throw new NullReferenceException( "ITextDocumentSnapshot is null" );
var editorAdaptersFactoryService = await EditorAdaptersFactoryService.GetServiceAsync();
var textManager = await TextManager.GetServiceAsync();
ErrorHandler.ThrowOnFailure( textManager.GetActiveView( 1, null, out var activeTextView ) );
var wpfTextViewHost = editorAdaptersFactoryService.GetWpfTextViewHost( activeTextView ) ?? throw new NullReferenceException( "IWpfTextViewHost is null" );
var wpfTextView = wpfTextViewHost.TextView ?? throw new NullReferenceException( "IwpfTextView is null" );
var wpfTextViewMargin = wpfTextViewHost.GetTextViewMargin( PredefinedMarginNames.LineNumber ) ?? throw new NullReferenceException( "IWpfTextViewMargin is null" );
var path = $"D:/Snapshots/{DateTime.UtcNow.Ticks}-{Path.GetFileNameWithoutExtension( textViewSnapshot.FilePath ).Replace( ".", "_" )}.gif";
TakeSnapshot( path, wpfTextView, wpfTextViewMargin );
await Extensibility.Shell().ShowPromptAsync( $"Snapshot was saved: " + path, PromptOptions.OK, cancellationToken );
} catch (Exception ex) {
Logger.TraceInformation( "Can not save snapshot: " + ex );
}
}
Unfortunately, margin.VisualElement.UpdateLayout(); doesn't work!!!
private static void TakeSnapshot(string path, IWpfTextView view, IWpfTextViewMargin margin) {
ThreadHelper.ThrowIfNotOnUIThread();
Directory.CreateDirectory( Path.GetDirectoryName( path ) );
using (var stream = File.Create( path )) {
var encoder = new GifBitmapEncoder();
TakeSnapshot( encoder, view, margin );
encoder.Save( stream );
}
}
private static void TakeSnapshot(BitmapEncoder encoder, IWpfTextView view, IWpfTextViewMargin margin) {
ThreadHelper.ThrowIfNotOnUIThread();
var element = GetRoot( view.VisualElement );
{
view.ViewportLeft = 0;
view.DisplayTextLineContainingBufferPosition( new SnapshotPoint( view.TextSnapshot, 0 ), 0, ViewRelativePosition.Top );
view.Caret.MoveTo( new SnapshotPoint( view.TextSnapshot, 0 ), PositionAffinity.Predecessor );
element.UpdateLayout();
margin.VisualElement.UpdateLayout();
TakeSnapshot2( encoder, element );
}
while (view.TextViewLines.LastVisibleLine.End.Position < view.TextSnapshot.Length) {
view.ViewScroller.ScrollViewportVerticallyByPixels( -10 );
element.UpdateLayout();
margin.VisualElement.UpdateLayout();
TakeSnapshot2( encoder, element );
}
}
private static void TakeSnapshot2(BitmapEncoder encoder, FrameworkElement element) {
ThreadHelper.ThrowIfNotOnUIThread();
var renderTargetBitmap = new RenderTargetBitmap( (int) element.ActualWidth, (int) element.ActualHeight, 96, 96, PixelFormats.Pbgra32 );
renderTargetBitmap.Render( element );
encoder.Frames.Add( BitmapFrame.Create( renderTargetBitmap ) );
}
private static FrameworkElement GetRoot(FrameworkElement element) {
ThreadHelper.ThrowIfNotOnUIThread();
while (element.GetVisualOrLogicalParent() != null) {
element = (FrameworkElement) element.GetVisualOrLogicalParent();
}
return element;
}
}
Metadata
Metadata
Assignees
Labels
No labels