65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中使用 Microsoft.DirectX.AudioVideoPlayback 实现异步进度

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2010年12月3日

CPOL

6分钟阅读

viewsIcon

36484

downloadIcon

1335

自定义窗口控件,模仿 Windows 7 的调暗和异步 Aero 进度动画。

Asynchronous DirectX TreeView

引言

最近,我需要一个带复选框treeview,以便最终用户能够选择文件夹和文件,并显示与之关联的“windows”图标。由于枚举目录可能会很麻烦,我还想在treeview上显示一个 aero 风格的指示器,而不会禁用整个窗体。

背景

我绝不是天才,而且我发现我年纪越大,记忆力就越差。我经常在 CodeProject 上搜索一些零碎的知识来帮助我解决正在处理的问题,或者回忆起我做过但已经忘记的事情。自从我于 2006 年成为会员以来,我想是时候回馈一些东西了!这并不是我正在进行工作的完整实现,但它是作为我的其他控件模板而创建的控件之一。

在搜索 CodeProject 时,我找到了 Paul Ingles 提交的文章 使用 C# 中的 SHGetFileInfo 获取(并管理)文件和文件夹图标,这是一篇关于获取“windows”图标的非常好的文章。我还找到了 Nathan B. Evans 提交的文章 WinForms 的 AJAX 风格异步进度对话框,这是一篇关于在 Windows 窗体上实现 aero 风格指示器的非常好的文章。我强烈建议您查阅这两篇文章。

虽然我喜欢 Nathan 在他的动画方面所做的工作,但我希望在控件中使用预先构建的.gif图像,而不是覆盖整个窗体,并且我希望能够使用我在其他地方使用过的相同动画。当启动后台进程时,在PictureBox控件中实现动画.gif是徒劳的。这促使我使用.avi,就像 Windows 所做的那样,因此我使用了我之前在其他解决方案中使用过的Microsoft.DirectX.AudioVideoPlayback

我需要解决的第一个问题是将动画.gif转换为.avi。为此,我使用了Animated GIF Banner Maker,这是一款用于从图形文件制作动画 GIF 横幅文件的软件。它支持以下图像格式:*.bmp*.gif*.jpg*.tga*.png*.ico*.wmf*.emf*.sgi*.dib*.icb*.pcx*.pcd*.psp*.pbm*.pgm*.psd*.ppm*.psg*.vst*.vda*.tif*.wbmp*.rle

Animated GIF Banner Maker

这个工具的优点是它有一个将动画 GIF 转换为 AVI 的实用程序,我用它创建了包含在源代码中的 AVI。这是他们产品网站的链接,Animated GIF Banner Maker,您可以在那里下载试用版。您不需要购买它就可以运行 GIF 到 AVI 的转换实用程序,但是,如果您需要创建动画 GIF...可以尝试试用版!

实现这一切需要三个控件

  • AviPlayerEx.cs。处理播放、停止和重置Microsoft.DirectX.AudioVideoPlayback的所有逻辑。
  • ImageListsEx.cs。处理从 API 调用返回的 Windows 图标的检索和缓存的所有逻辑。
    我按如下方式使用了 Nathan 的代码(Nathan 的版权包含在源代码中)
    • 我使用了他AsyncBaseDialog.cs类中BeginAsyncIndication方法的快照逻辑来创建Gdi32.GetSnapshot()方法。我在Gdi32.cs文件中创建了这个方法,以便我可以将此逻辑用于我创建的其他控件。由于我不希望对整个窗体产生效果,因此我创建了TreeViewEx控件,其中包含TreeViewPictureBox。该方法接受两个参数,“源”控件(在此例中为TreeViewEx.TreeView控件,“ctlTreeView”)和“目标”控件(在此例中为TreeViewEx.PictureBox控件“ctlSnapShot”)。
    • 我将FillBrushOpacity225更改为128,使其更具透明度。
    • 我已从使用Panel切换到在TreeViewEx控件中使用PictureBoxTreeViewEx.PictureBoxTreeViewEx.TreeView小 2x2 像素,并且相对于其位置偏移 1x1 像素。当我将快照图形显示在TreeViewEx.PictureBox中时,TreeViewEx.TreeView会显得被禁用而没有移动,保留了TreeViewEx.TreeView的边框。TreeViewEx.PictureBox还能阻止用户在处理完成之前对TreeViewEx.TreeView执行任何其他操作,并能干净地隐藏处理TreeViewEx.TreeView时发生的任何闪烁。
    • 我也没有使用他的BlurGrayscale方法,因此我从我的方法中删除了相关逻辑。
  • TreeViewEx.cs。使用其他控件来存储图标和显示进度,处理枚举驱动器、文件夹和文件的所有逻辑。
    我按如下方式使用了 Paul 的代码
    • 我将 Paul 的代码从两个类合并到了我的ImageListsEx.cs控件类中。虽然在这个演示中我只使用了SmallImageList,但通过简单地用IconSize.Multiple初始化控件,并将ListView设置为使用SmallImageListLargeImageList属性,我就可以为ListView使用相同的ImageListsEx控件。
    • 我修改了GetFolderIcon()以使用文件夹路径而不是“null”,这样我就可以获取 Windows 可能正在为文件夹使用的任何“特殊”图标,而不是通用的打开和关闭图标。同样,这些图标是缓存的。
    • 我添加了GetDriveIcon()方法来检索每种驱动器类型的已注册 Windows 图标。同样,这些图标也是缓存的。
    • 我删除了“_extensionListHashTable,并使用了ImageList.Images ImageListCollection提供的相同功能。

Using the Code

实现该控件非常简单,只需将AviPlayerEx.csImageListsEx.csTreeViewEx.cs文件添加到您的项目中,或者将它们构建到自己的 DLL 中。将TreeViewEx.cs控件拖到您的窗体上,并连接以下事件

  • OnBusyStateChanged。这是一个自定义委托BooleanHandler (Boolean value)事件处理程序,当TreeViewEx开始处理请求时引发True,当请求完成时引发False。这允许您添加自定义处理以在需要时更改控件状态。
    private void BusyStateChanged(Boolean busy) {
    	this.btnShow.Enabled = this.btnClose.Enabled = !busy;
    }
  • OnPublishException。这是一个自定义委托ExceptionHandler (Exception exception)事件处理程序,它将来自TreeViewEx的异常传递给父级进行处理、记录或显示。
    private void PublishException(Exception exception) {
    	MessageBox.Show(exception.Message);
    }
  • OnPublishStatus。这是一个自定义委托TextHandler (String value)事件处理程序,它将来自TreeViewExstring信息传递给父级,用于显示TreeViewEx当前正在执行的操作。
    private void PublishStatus(String text) {
    	this.staStatus.Text = text;
    }

您需要实现 Nathan 使用的WndProc(ref Message m)来处理用户调整窗体大小、最大化、最小化、还原或双击窗体标题栏的操作...没必要重复造轮子...他的代码是有效的!

protected override void WndProc(ref Message m) {
   if (IsAsyncBusy) {
      if (m.Msg == 0x112 /* WM_SYSCOMMAND */) {
         int w = m.WParam.ToInt32();
 
         if (w == 0xf120 /* SC_RESTORE */ || w == 0xf030 
                         /* SC_MAXIMIZE */ || w == 0xf020 
                         /* SC_MINIMIZE */)
            return; // short circuit
 
      } else if (m.Msg == 0xa3 /* WM_NCLBUTTONDBLCLK */)
         return; // short circuit
   }
 
   base.WndProc(ref m);
}

您还需要在FormClosing(object sender, FormClosingEventArgs e)方法中处理Cancel事件,以防止用户在TreeViewEx处理请求时关闭窗体。

private void DemoForm_FormClosing(object sender, FormClosingEventArgs e) {
	e.Cancel = this.tvwExplorer.IsAsyncBusy;
}

最后,您需要在窗体的Form_Load方法中调用TreeViewEx.Initialize()方法来启动一切。

private void DemoForm_Load(object sender, EventArgs e) {
//----------------------------------------------------------------------------------------
//..If you're persisting their selections, then you need to add them 
// before initializing the TreeViewEx control. You can use the 
//..	List<string> "Selections" property defined within the TreeViewEx control...
//----------------------------------------------------------------------------------------
	this.tvwExplorer.Selections.Add(@"C:\Windows\addins");
//----------------------------------------------------------------------------------------
//..	...or you can manage you own List<string> & set/get the property as follows...
//----------------------------------------------------------------------------------------
//	List<string> mySelections = new List<String>();
//	mySelections.Add(@"C:\Windows\addins");
//	this.tvwExplorer.Selections = mySelections;
//----------------------------------------------------------------------------------------
//..	...and when you need to get it back...
//----------------------------------------------------------------------------------------
//	mySelections = this.tvwExplorer.Selections;
//----------------------------------------------------------------------------------------
	this.tvwExplorer.Initialize();
	Application.DoEvents();
}

要真正“看到”它的实际运行效果,您需要深入到Windows\System32文件夹。

关注点

在 Microsoft Visual Studio IDE 中运行AviPlayerEx.cs控件时,可能会抛出LoadLock被检测到错误。我已注释掉出现此问题的代码以及如何“修复”它。运行可执行文件时不会出现此错误。

public void Open(String fileName, Size size, Boolean continous) {
	if (mdxAviPlayer != null) {mdxAviPlayer.Dispose();}
//------------------------------------------------------------------------------------
//..Within the Visual Studio IDE the following error is thrown when 
//executing "mdxAviPlayer = new Video(fileName)"...
//------------------------------------------------------------------------------------
//..	LoadLock was detected. DLL 'C:\Windows\assembly\GAC\
// 	Microsoft.DirectX\1.0.2902.0__31bf3856ad364e35\Microsoft.DirectX.dll' 
//..	is attempting managed execution inside OS Loader lock. 
//	Do not attempt to run managed code inside a DllMain or image 
//..	initialization function since doing so can cause the application to hang.
//------------------------------------------------------------------------------------
//..The only work around I've found is the following, since this is an error 
// being thrown from the OS to the MDA... 
//------------------------------------------------------------------------------------
//..	Within the Visual Studio IDE select "Debug | Exceptions". 
//..	Expand "Managed Debug Assistants". 
//..	Deselect "Thrown" for "Loader Lock".
//..	Select the "OK" button.
//------------------------------------------------------------------------------------
	mdxAviPlayer = new Video(fileName);
	if (continous) {mdxAviPlayer.Ending += new EventHandler(Ending);}
	mdxAviPlayer.Owner = this; this.Size = size;
	mfContinous = continous;
}

谢谢

感谢阅读!如果您对控件有任何修改、错误修复或增强功能想要分享,请在评论区发布您的源代码片段和/或想法。

历史

  • 2010 年 12 月 1 日 - 首次发布
© . All rights reserved.