如何打开 Excel 文件并在 WPF 中查看?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15870215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to open an Excel file and view in WPF?
提问by Gayashan
Im creating some excel files using my c# application and save them in my pc. I want to open and view them inside my application how can i do it? My application is developed using WPF C#
我使用我的 c# 应用程序创建了一些 excel 文件并将它们保存在我的电脑中。我想在我的应用程序中打开并查看它们,我该怎么做?我的应用程序是使用 WPF C# 开发的
采纳答案by Haritha
You can use DocumentViewerWPF control.
您可以使用DocumentViewerWPF 控件。
First you should convert your office documentto XPSformat.
Please look at this post.
首先,您应该将您office document的XPS格式转换为格式。请看这篇文章。
And then bind it to the Documentproperty of the DocumentViewerControl.
然后将其绑定到控件的Document属性上DocumentViewer。
XAML
XAML
<DocumentViewer Name="myDocumentViewer" Margin="0,0,0,59">
</DocumentViewer>
Code Behind
背后的代码
myDocumentViewer.Document = this.ConvertPptxDocToXPSDoc(this.FileName, this.newXPSDocumentName).GetFixedDocumentSequence();
回答by SHSE
You could utilize preview handlers mechanism. Here is the control I made to host a preview handler:
您可以利用预览处理程序机制。这是我用来托管预览处理程序的控件:
public class FilePreviewControl : HwndHost {
private const int
Child = 0x40000000,
Visible = 0x10000000,
HostId = 0x00000002,
ClipChild = 0x02000000;
public static readonly DependencyProperty PathProperty = DependencyProperty.Register(
"Path", typeof (string), typeof (FilePreviewControl), new UIPropertyMetadata(Update));
public static readonly DependencyProperty ExtensionProperty = DependencyProperty.Register(
"Extension", typeof (string), typeof (FilePreviewControl), new UIPropertyMetadata(Update));
public static readonly DependencyProperty SourceStreamProperty = DependencyProperty.Register(
"SourceStream", typeof (Stream), typeof (FilePreviewControl), new UIPropertyMetadata(Update));
private readonly PreviewManager manager;
private IntPtr hwndHost;
public FilePreviewControl() {
this.manager = new PreviewManager();
}
public Stream SourceStream {
get { return (Stream) this.GetValue(SourceStreamProperty); }
set { this.SetValue(SourceStreamProperty, value); }
}
public string Extension {
get { return (string) this.GetValue(ExtensionProperty); }
set { this.SetValue(ExtensionProperty, value); }
}
public string Path {
get { return (string) this.GetValue(PathProperty); }
set { this.SetValue(PathProperty, value); }
}
private static void Update(DependencyObject d, DependencyPropertyChangedEventArgs e) {
((FilePreviewControl) d).RefreshPreview();
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent) {
this.hwndHost = IntPtr.Zero;
this.hwndHost = CreateWindowEx(0, "static", "",
Child | Visible | ClipChild,
0, 0,
(int) this.ActualWidth, (int) this.ActualHeight,
hwndParent.Handle,
(IntPtr) HostId,
IntPtr.Zero,
0);
this.RefreshPreview();
return new HandleRef(this, this.hwndHost);
}
protected override void DestroyWindowCore(HandleRef hwnd) {
DestroyWindow(hwnd.Handle);
this.manager.Dispose();
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) {
base.OnRenderSizeChanged(sizeInfo);
var rect = new Rect(new Size(this.ActualWidth, this.ActualHeight));
this.manager.InvalidateAttachedPreview(rect);
}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
handled = false;
return IntPtr.Zero;
}
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
private static extern IntPtr CreateWindowEx(
int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x,
int y,
int width,
int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,
[MarshalAs(UnmanagedType.AsAny)] object pvParam);
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
private static extern bool DestroyWindow(IntPtr hwnd);
private void RefreshPreview() {
if (this.hwndHost == IntPtr.Zero)
return;
var filePath = this.Path;
var extension = this.Extension;
if (string.IsNullOrEmpty(extension) && !string.IsNullOrEmpty(filePath))
extension = System.IO.Path.GetExtension(filePath);
var shouldBeDeactivated =
this.Visibility != Visibility.Visible ||
(string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) && this.SourceStream == null ||
string.IsNullOrEmpty(extension);
if (shouldBeDeactivated) {
this.manager.Detach();
return;
}
var rect = new Rect(new Size(this.RenderSize.Width, this.RenderSize.Height));
try {
this.manager.AttachPreview(
this.hwndHost,
rect,
extension,
filePath,
this.SourceStream);
} catch (Exception exception) {
Trace.TraceError(exception.ToString());
}
}
public static bool CanPreview(string extension) {
return PreviewManager.GetPreviewHandlerKey(extension) != null;
}
#region Nested type: InteropStream
private sealed class InteropStream : IStream, IDisposable {
private readonly Stream stream;
private bool disposed;
public InteropStream(Stream sourceStream) {
if (sourceStream == null)
throw new ArgumentNullException("sourceStream");
this.stream = sourceStream;
}
#region IDisposable Members
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#region IStream Members
public void Clone(out IStream ppstm) {
throw new NotSupportedException();
}
public void Commit(int grfCommitFlags) {
throw new NotSupportedException();
}
public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) {
throw new NotSupportedException();
}
public void LockRegion(long libOffset, long cb, int dwLockType) {
throw new NotSupportedException();
}
[SecurityCritical]
public void Read(byte[] pv, int cb, IntPtr pcbRead) {
var count = this.stream.Read(pv, 0, cb);
if (pcbRead != IntPtr.Zero)
Marshal.WriteInt32(pcbRead, count);
}
public void Revert() {
throw new NotSupportedException();
}
[SecurityCritical]
public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) {
var origin = (SeekOrigin) dwOrigin;
var pos = this.stream.Seek(dlibMove, origin);
if (plibNewPosition != IntPtr.Zero)
Marshal.WriteInt64(plibNewPosition, pos);
}
public void SetSize(long libNewSize) {
this.stream.SetLength(libNewSize);
}
public void Stat(out STATSTG pstatstg, int grfStatFlag) {
pstatstg = new STATSTG {
type = 2,
cbSize = this.stream.Length,
grfMode = 0
};
if (this.stream.CanRead && this.stream.CanWrite)
pstatstg.grfMode |= 2;
else if (this.stream.CanWrite && !this.stream.CanRead)
pstatstg.grfMode |= 1;
else
throw new IOException();
}
public void UnlockRegion(long libOffset, long cb, int dwLockType) {
throw new NotSupportedException();
}
[SecurityCritical]
public void Write(byte[] pv, int cb, IntPtr pcbWritten) {
this.stream.Write(pv, 0, cb);
if (pcbWritten != IntPtr.Zero)
Marshal.WriteInt32(pcbWritten, cb);
}
#endregion
private void Dispose(bool disposing) {
if (this.disposed)
return;
if (disposing && this.stream != null)
this.stream.Dispose();
this.disposed = true;
}
~InteropStream() {
this.Dispose(false);
}
}
#endregion
private sealed class TempFile : IDisposable {
private string path;
public TempFile() : this(System.IO.Path.GetTempFileName()) {
}
private TempFile(string path) {
if (string.IsNullOrEmpty(path))
throw new ArgumentNullException("path");
this.path = path;
}
public string Path {
get {
if (this.path == null)
throw new ObjectDisposedException(this.GetType().Name);
return this.path;
}
}
#region IDisposable Members
public void Dispose() {
this.Dispose(true);
}
#endregion
private void Dispose(bool disposing) {
if (disposing)
GC.SuppressFinalize(this);
if (this.path == null)
return;
try {
File.Delete(this.path);
} catch {
Trace.TraceWarning("Can't delete file " + this.path);
} // best effort
this.path = null;
}
~TempFile() {
this.Dispose(false);
}
}
#region Nested type: PreviewManager
private sealed class PreviewManager : IDisposable {
private IPreviewHandler currentHandler;
private bool disposed;
private InteropStream stream;
#region IDisposable Members
public void Dispose() {
this.DisposeInternal();
GC.SuppressFinalize(this);
}
#endregion
public void AttachPreview(IntPtr handler, Rect viewRect, string extension, string filePath,
Stream sourceStream) {
this.Unload();
var classKey = GetPreviewHandlerKey(extension);
if (classKey == null)
return;
var guid = new Guid(classKey.GetValue(string.Empty).ToString());
var type = Type.GetTypeFromCLSID(guid, true);
var instance = Activator.CreateInstance(type);
var fileInit = instance as IInitializeWithFile;
var streamInit = instance as IInitializeWithStream;
if (streamInit != null && sourceStream != null) {
this.stream = new InteropStream(sourceStream);
streamInit.Initialize(this.stream, 0);
} else if (fileInit != null)
if (filePath != null)
fileInit.Initialize(filePath, 0);
else if (sourceStream != null)
using (var tempFile = new TempFile()) {
using (var fileStream = File.Create(tempFile.Path))
sourceStream.CopyTo(fileStream);
fileInit.Initialize(tempFile.Path, 0);
}
else
return;
else
return;
this.currentHandler = instance as IPreviewHandler;
if (this.currentHandler == null) {
this.Unload();
return;
}
var rect = new ShellRect(viewRect);
this.currentHandler.SetWindow(handler, ref rect);
this.currentHandler.SetRect(ref rect);
try {
this.currentHandler.DoPreview();
} catch {
this.Unload();
throw;
}
}
internal static RegistryKey GetPreviewHandlerKey(string extension) {
var commonGuid = new Guid("8895b1c6-b41f-4c1c-a562-0d564250836f");
var classKey =
Registry.ClassesRoot.OpenSubKey(string.Format(@"{0}\ShellEx\{1:B}", extension, commonGuid));
return classKey;
}
public void Detach() {
this.Unload();
}
public void InvalidateAttachedPreview(Rect viewRect) {
if (this.currentHandler == null)
return;
var rect = new ShellRect(viewRect);
this.currentHandler.SetRect(ref rect);
}
private void DisposeInternal() {
if (this.disposed)
return;
this.Unload();
this.disposed = true;
}
private void Unload() {
if (this.currentHandler != null) {
this.currentHandler.Unload();
Marshal.FinalReleaseComObject(this.currentHandler);
this.currentHandler = null;
}
if (this.stream != null) {
this.stream.Dispose();
this.stream = null;
}
}
~PreviewManager() {
this.DisposeInternal();
}
#region Nested type: IInitializeWithFile
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b7d14566-0509-4cce-a71f-0a554233bd9b")]
internal interface IInitializeWithFile {
void Initialize([MarshalAs(UnmanagedType.LPWStr)] string pszFilePath, uint grfMode);
}
#endregion
#region Nested type: IInitializeWithStream
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b824b49d-22ac-4161-ac8a-9916e8fa3f7f")]
internal interface IInitializeWithStream {
void Initialize(IStream pstream, uint grfMode);
}
#endregion
#region Nested type: IPreviewHandler
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("8895b1c6-b41f-4c1c-a562-0d564250836f")]
internal interface IPreviewHandler {
void SetWindow(IntPtr hwnd, ref ShellRect rect);
void SetRect(ref ShellRect rect);
void DoPreview();
void Unload();
void SetFocus();
void QueryFocus(out IntPtr phwnd);
[PreserveSig]
uint TranslateAccelerator(ref MSG pmsg);
}
#endregion
#region Nested type: ShellRect
[StructLayout(LayoutKind.Sequential)]
internal struct ShellRect {
public readonly int left;
public readonly int top;
public readonly int right;
public readonly int bottom;
public ShellRect(Rect rect) {
this.top = (int) rect.Top;
this.bottom = (int) rect.Bottom;
this.left = (int) rect.Left;
this.right = (int) rect.Right;
}
}
#endregion
}
#endregion
}
And here is how to use it:
这是如何使用它:
<local:FilePreviewControl Path="Book1.xlsx" />
It will work only if you have Microsoft Office installed on your computer.
只有在您的计算机上安装了 Microsoft Office 时,它才会起作用。
回答by Flou
The solution from SHSE is underestimate. It works perfectly and the advantages are :
上海证券交易所的解决方案被低估了。它完美运行,优点是:
- no activeX msgBox (open, save, cancel) like in the WebBrowser solution
- no need to regsvr32 dsoframer.ocx as admin in client machine with the AxFramerControl solution
- no need to convert in XPS format, so you can keep Excel style
- 没有像 WebBrowser 解决方案中的 activeX msgBox(打开、保存、取消)
- 无需使用 AxFramerControl 解决方案在客户端机器中将 regsvr32 dsoframer.ocx 设为管理员
- 无需转换成XPS格式,保持Excel风格
Drawbacks are :
缺点是:
- Office is required
- have to find a way to terminate Excel process when the app is closing on Windows 7 (no need on Windows 10, Excel terminate itself)
- the document is readonly
- 需要办公室
- 当应用程序在 Windows 7 上关闭时,必须找到一种方法来终止 Excel 进程(在 Windows 10 上不需要,Excel 会自行终止)
- 文档是只读的
You just have to add :
你只需要添加:
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
using System.Security.AccessControl;
and add the latest Microsoft.Office.Interop.Excel reference
并添加最新的 Microsoft.Office.Interop.Excel 参考
I wanted to just add a comment but I don't have enough reputation. However, this solution can save you days !
我只想添加评论,但我没有足够的声誉。但是,此解决方案可以为您节省几天时间!

