The Application.OpenDocumentFile(ModelPath, OpenOptions) method can be used to set options related to opening a workshared document. In addition to options to detach from the central document or to allow a local file to be opened ReadOnly by a user other than its owner, options may also be set related to worksets. When a workshared document is opened, all system worksets are automatically opened, however user-created worksets can be specified to be opened or closed. Elements in an open workset can be expanded and displayed. However, elements in a closed workset are not displayed to avoid expanding them. By only opening worksets necessary in the current session, Revit's memory footprint is reduced, which can help with performance.
In the example below, a document is opened with two worksets specified to be opened. Note that the WorksharingUtils.GetUserWorksetInfo() method can be used to access workset information from a closed Revit document.
Code Region: Open Workshared Document |
Document OpenDocumentWithWorksets(Application app, ModelPath projectPath) { Document doc = null; try { // Get info on all the user worksets in the project prior to opening IList<WorksetPreview> worksets = WorksharingUtils.GetUserWorksetInfo(projectPath); IList<WorksetId> worksetIds = new List<WorksetId>(); // Find two predetermined worksets foreach (WorksetPreview worksetPrev in worksets) { if (worksetPrev.Name.CompareTo("Workset1") == 0 || worksetPrev.Name.CompareTo("Workset2") == 0) { worksetIds.Add(worksetPrev.Id); } } OpenOptions openOptions = new OpenOptions(); // Setup config to close all worksets by default WorksetConfiguration openConfig = new WorksetConfiguration(WorksetConfigurationOption.CloseAllWorksets); // Set list of worksets for opening openConfig.Open(worksetIds); openOptions.SetOpenWorksetsConfiguration(openConfig); doc = app.OpenDocumentFile(projectPath, openOptions); } catch (Exception e) { TaskDialog.Show("Open File Failed", e.Message); } return doc; } |
Another option is to open the document while just opening the last viewed worksets.
Code Region: Open last viewed worksets |
public static Document OpenLastViewed(UIApplication uiApplication) { Application application = uiApplication.Application; // Setup options OpenOptions options1 = new OpenOptions(); // Default config opens all. Close all first, then open last viewed to get the correct settings. WorksetConfiguration worksetConfig = new WorksetConfiguration(WorksetConfigurationOption.OpenLastViewed); options1.SetOpenWorksetsConfiguration(worksetConfig); // Open the document Document openedDoc = application.OpenDocumentFile(GetWSAPIModelPath("WorkaredFileSample.rvt"), options1); return openedDoc; } private static ModelPath GetWSAPIModelPath(string fileName) { // Utility to get a local path for a target model file FileInfo filePath = new FileInfo(Path.Combine(@"C:\Documents\Revit Projects", fileName)); ModelPath mp = ModelPathUtils.ConvertUserVisiblePathToModelPath(filePath.FullName); return mp; } |
Code Region: Open new local from disk |
public static Document OpenNewLocalFromDisk(UIApplication uiApplication) { // Create new local from a disk location ModelPath newLocalPath = GetWSAPIModelPath("LocalWorksharing.rvt"); return (OpenNewLocalFromModelPath(uiApplication.Application, GetWSAPIModelPath("NewLocalWorksharing.rvt"), newLocalPath)); } private static Document OpenNewLocalFromModelPath(Application app, ModelPath centralPath, ModelPath localPath) { // Create the new local at the given path WorksharingUtils.CreateNewLocal(centralPath, localPath); // Select specific worksets to open // First get a list of worksets from the unopened document IList<WorksetPreview> worksets = WorksharingUtils.GetUserWorksetInfo(localPath); List<WorksetId> worksetsToOpen = new List<WorksetId>(); foreach (WorksetPreview preview in worksets) { // Match worksets to open with criteria if (preview.Name.StartsWith("O")) worksetsToOpen.Add(preview.Id); } // Setup option to open the target worksets // First close all, then set specific ones to open WorksetConfiguration worksetConfig = new WorksetConfiguration(WorksetConfigurationOption.CloseAllWorksets); worksetConfig.Open(worksetsToOpen); // Open the new local OpenOptions options1 = new OpenOptions(); options1.SetOpenWorksetsConfiguration(worksetConfig); Document openedDoc = app.OpenDocumentFile(localPath, options1); return openedDoc; } |
Code Region: Open new local from Revit Server |
/// <summary> /// Get the server path for a particular model and open a new local copy /// </summary> public static Document OpenNewLocalFromServer(UIApplication uiApp) { // Create new local from a server location Application app = uiApp.Application; // Get the host id/IP of the server String hostId = app.GetRevitServerNetworkHosts().First(); // try to get the server path for the particular model on the server String rootFolder = "|"; ModelPath serverPath = FindWSAPIModelPathOnServer(app, hostId, rootFolder, "WorksharingOnServer.rvt"); ModelPath newLocalPath = GetWSAPIModelPath("WorksharingLocalFromServer.rvt"); return (OpenNewLocalFromModelPath(uiApp.Application, serverPath, newLocalPath)); } /// <summary> /// Uses the Revit Server REST API to recursively search the folders of the Revit Server for a particular model. /// </summary> private static ModelPath FindWSAPIModelPathOnServer(Application app, string hostId, string folderName, string fileName) { // Connect to host to find list of available models (the "/contents" flag) XmlDictionaryReader reader = GetResponse(app, hostId, folderName + "/contents"); bool found = false; // Look for the target model name in top level folder List<String> folders = new List<String>(); while (reader.Read()) { // Save a list of subfolders, if found if (reader.NodeType == XmlNodeType.Element && reader.Name == "Folders") { while (reader.Read()) { if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Folders") break; if (reader.NodeType == XmlNodeType.Element && reader.Name == "Name") { reader.Read(); folders.Add(reader.Value); } } } // Check for a matching model at this folder level if (reader.NodeType == XmlNodeType.Element && reader.Name == "Models") { found = FindModelInServerResponseJson(reader, fileName); if (found) break; } } reader.Close(); // Build the model path to match the found model on the server if (found) { // Server URLs use "|" for folder separation, Revit API uses "/" String folderNameFragment = folderName.Replace('|', '/'); // Add trailing "/" if not present if (!folderNameFragment.EndsWith("/")) folderNameFragment += "/"; // Build server path ModelPath modelPath = new ServerPath(hostId, folderNameFragment + fileName); return modelPath; } else { // Try subfolders foreach (String folder in folders) { ModelPath modelPath = FindWSAPIModelPathOnServer(app, hostId, folder, fileName); if (modelPath != null) return modelPath; } } return null; } // This string is different for each RevitServer version private static string s_revitServerVersion = "/RevitServerAdminRESTService2014/AdminRESTService.svc/"; /// <summary> /// Connect to server to get list of available models and return server response /// </summary> private static XmlDictionaryReader GetResponse(Application app, string hostId, string info) { // Create request WebRequest request = WebRequest.Create("http://" + hostId + s_revitServerVersion + info); request.Method = "GET"; // Add the information the request needs request.Headers.Add("User-Name", app.Username); request.Headers.Add("User-Machine-Name", app.Username); request.Headers.Add("Operation-GUID", Guid.NewGuid().ToString()); // Read the response XmlDictionaryReaderQuotas quotas = new XmlDictionaryReaderQuotas(); XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader(request.GetResponse().GetResponseStream(), quotas); return jsonReader; } /// <summary> /// Read through server response to find particular model /// </summary> private static bool FindModelInServerResponseJson(XmlDictionaryReader reader, string fileName) { // Read through entries in this section while (reader.Read()) { if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Models") break; if (reader.NodeType == XmlNodeType.Element && reader.Name == "Name") { reader.Read(); String modelName = reader.Value; if (modelName.Equals(fileName)) { // Match found, stop looping and return return true; } } } return false; } |
If an add-in will be working on a workshared file but does not need to make permanet changes, it can open the model detached from the central file.
Code Region: Open detached |
private static Document OpenDetached(Application application, ModelPath modelPath) { OpenOptions options1 = new OpenOptions(); options1.DetachFromCentralOption = DetachFromCentralOption.DetachAndDiscardWorksets; Document openedDoc = application.OpenDocumentFile(modelPath, options1); return openedDoc; } |
Code Region: Copy and open detached |
public static Document CopyAndOpenDetached(UIApplication uiApp) { // Copy a server model locally and open detached Application application = uiApp.Application; String hostId = application.GetRevitServerNetworkHosts().First(); // Try to get the server path for the particular model on the server String rootFolder = "|"; ModelPath serverPath = FindWSAPIModelPathOnServer(application, hostId, rootFolder, "ServerModel.rvt"); // For debugging String sourcePath = ModelPathUtils.ConvertModelPathToUserVisiblePath(serverPath); // Setup the target location for the copy ModelPath localPath = GetWSAPIModelPath("CopiedModel.rvt"); // Copy, allowing overwrite application.CopyModel(serverPath, ModelPathUtils.ConvertModelPathToUserVisiblePath(localPath), true); // Open the copy as detached Document openedDoc = OpenDetached(application, localPath); return openedDoc; } |