WPF应用程序在底层使用 DirectX ,无论设计复杂的3D图形(这是 DirectX 的特长所在)还是绘制简单的按钮与文本,所有绘图工作都是通过 DirectX 管线完成的。在硬件加速方面也带来了好处,DirectX 在渲染图形时会将尽可能多的工作递交给图形处理单元(GPU)去处理,GPU是显卡的专用处理器。
  WPF凭借着出色的3D渲染能力,使其成为在客户端加载渲染3D模型不二的选择。在3D模型查看器中加载BIM文件(.ifc格式),显示效果如下图所示:
xBIM 实战03 使用WPF技术实现IFC模型的加载与浏览-LMLPHP

主要业务逻辑如下:

         /// <summary>
/// 加载模型文件
/// </summary>
/// <param name="modelFileName"></param>
public void LoadAnyModel(string modelFileName)
{
var fInfo = new FileInfo(modelFileName);
if (!fInfo.Exists)
return; if (fInfo.FullName.ToLower() == GetOpenedModelFileName())
return; // 没有撤回功能;如果在这一点之后失败,那么应该关闭当前文件。
CloseAndDeleteTemporaryFiles();
SetOpenedModelFileName(modelFileName.ToLower());
ProgressStatusBar.Visibility = Visibility.Visible;
SetWorkerForFileLoad(); var ext = fInfo.Extension.ToLower();
switch (ext)
{
case ".ifc": // Ifc 文件
case ".ifcxml": // IfcXml 文件
case ".ifczip": // zip 文件,包含 xbim 或者 ifc 文件
case ".zip": // zip 文件,包含 xbim 或者 ifc 文件
case ".xbimf":
case ".xbim":
_loadFileBackgroundWorker.RunWorkerAsync(modelFileName);
break;
default:
Logger.LogWarning("Extension '{extension}' has not been recognised.", ext);
break;
}
}

其中调用的主要方法如下:

         /// <summary>
/// 整理所有打开的文件并关闭所有打开的模型
/// </summary>
private void CloseAndDeleteTemporaryFiles()
{
try
{
if (_loadFileBackgroundWorker != null && _loadFileBackgroundWorker.IsBusy)
{
_loadFileBackgroundWorker.CancelAsync(); //通知线程取消操作
} SetOpenedModelFileName(null);
if (Model != null)
{
Model.Dispose();
ModelProvider.ObjectInstance = null;
ModelProvider.Refresh();
} if (!(DrawingControl.DefaultLayerStyler is SurfaceLayerStyler))
{
SetDefaultModeStyler(null, null);
}
}
finally
{
if (!(_loadFileBackgroundWorker != null && _loadFileBackgroundWorker.IsBusy && _loadFileBackgroundWorker.CancellationPending)) //它仍然在运行,但已经取消了
{
if (!string.IsNullOrWhiteSpace(_temporaryXbimFileName) && File.Exists(_temporaryXbimFileName))
{
File.Delete(_temporaryXbimFileName);
}
_temporaryXbimFileName = null;
}
else
{
//它将在工作线程中清除
}
}
}
         private void SetOpenedModelFileName(string ifcFilename)
{
_openedModelFileName = ifcFilename;
// 尝试通过用于多线程的委托更新窗口标题
Dispatcher.BeginInvoke(new Action(delegate
{
Title = string.IsNullOrEmpty(ifcFilename)
? "Xbim Xplorer"
: "Xbim Xplorer - [" + ifcFilename + "]";
}));
}
         private void SetWorkerForFileLoad()
{
_loadFileBackgroundWorker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_loadFileBackgroundWorker.ProgressChanged += OnProgressChanged;
_loadFileBackgroundWorker.DoWork += OpenAcceptableExtension;
_loadFileBackgroundWorker.RunWorkerCompleted += FileLoadCompleted;
}
        private void OnProgressChanged(object s, ProgressChangedEventArgs args)
{
if (args.ProgressPercentage < || args.ProgressPercentage > )
return; Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Send,
new Action(() =>
{
ProgressBar.Value = args.ProgressPercentage;
StatusMsg.Text = (string)args.UserState;
})); }
        private void OpenAcceptableExtension(object s, DoWorkEventArgs args)
{
var worker = s as BackgroundWorker;
var selectedFilename = args.Argument as string; try
{
if (worker == null)
throw new Exception("Background thread could not be accessed");
_temporaryXbimFileName = Path.GetTempFileName();
SetOpenedModelFileName(selectedFilename);
var model = IfcStore.Open(selectedFilename, null, null, worker.ReportProgress, FileAccessMode);
if (_meshModel)
{
// 匹配直接模型
if (model.GeometryStore.IsEmpty)
{
try
{
var context = new Xbim3DModelContext(model); if (!_multiThreading)
context.MaxThreads = ;
#if FastExtrusion
context.UseSimplifiedFastExtruder = _simpleFastExtrusion;
#endif
SetDeflection(model);
// 升级到新的几何图形表示,使用默认的三维模型
context.CreateContext(worker.ReportProgress, App.ContextWcsAdjustment);
}
catch (Exception geomEx)
{
var sb = new StringBuilder();
sb.AppendLine($"Error creating geometry context of '{selectedFilename}' {geomEx.StackTrace}.");
var newException = new Exception(sb.ToString(), geomEx);
Logger.LogError(, newException, "Error creating geometry context of {filename}", selectedFilename);
}
} // 匹配引用
foreach (var modelReference in model.ReferencedModels)
{
// 根据需要创建联合几何体上下文
Debug.WriteLine(modelReference.Name);
if (modelReference.Model == null)
continue;
if (!modelReference.Model.GeometryStore.IsEmpty)
continue;
var context = new Xbim3DModelContext(modelReference.Model);
if (!_multiThreading)
context.MaxThreads = ;
#if FastExtrusion
context.UseSimplifiedFastExtruder = _simpleFastExtrusion;
#endif
SetDeflection(modelReference.Model);
// 升级到新的几何图形表示,使用默认的三维模型
context.CreateContext(worker.ReportProgress, App.ContextWcsAdjustment);
}
if (worker.CancellationPending)
// 如果已请求取消,则不要打开结果文件
{
try
{
model.Close();
if (File.Exists(_temporaryXbimFileName))
{
File.Delete(_temporaryXbimFileName);
} _temporaryXbimFileName = null;
SetOpenedModelFileName(null);
}
catch (Exception ex)
{
Logger.LogError(, ex, "Failed to cancel open of model {filename}", selectedFilename);
}
return;
}
}
else
{
Logger.LogWarning("Settings prevent mesh creation.");
}
args.Result = model;
}
catch (Exception ex)
{
var sb = new StringBuilder();
sb.AppendLine($"Error opening '{selectedFilename}' {ex.StackTrace}.");
var newException = new Exception(sb.ToString(), ex);
Logger.LogError(, ex, "Error opening {filename}", selectedFilename);
args.Result = newException;
}
}
        private void FileLoadCompleted(object s, RunWorkerCompletedEventArgs args)
{
if (args.Result is IfcStore)
{
// 这将触发将模型加载到视图中的事件
ModelProvider.ObjectInstance = args.Result;
ModelProvider.Refresh();
ProgressBar.Value = ;
StatusMsg.Text = "Ready";
AddRecentFile();
}
else
{
var errMsg = args.Result as string;
if (!string.IsNullOrEmpty(errMsg))
{
MessageBox.Show(this, errMsg, "Error Opening File", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.None, MessageBoxOptions.None);
} var exception = args.Result as Exception;
if (exception != null)
{
var sb = new StringBuilder(); var indent = "";
while (exception != null)
{
sb.AppendFormat("{0}{1}\n", indent, exception.Message);
exception = exception.InnerException;
indent += "\t";
}
MessageBox.Show(this, sb.ToString(), "Error Opening Ifc File", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.None, MessageBoxOptions.None);
}
ProgressBar.Value = ;
StatusMsg.Text = "Error/Ready";
SetOpenedModelFileName("");
}
FireLoadingComplete(s, args);
}
         /// <summary>
/// 模型文件加载完成事件
/// </summary>
public event LoadingCompleteEventHandler LoadingComplete; private void FireLoadingComplete(object s, RunWorkerCompletedEventArgs args)
{
if (LoadingComplete != null)
{
LoadingComplete(s, args);
}
}
 
05-11 16:07