How to create a shared parameter that can be shared when project standards are transferred - c#

I am working on a project where I need to create multiple revit files consisting of wall types and create shared parameters into them. I completed this process.
But on manually clicking on Manage > Transfer Project Standards
Copy from "project name" > Wall Types through the revit interface.
I imported the wall types of different revit files created into one.
But the shared parameters seems to repeat in the type parameter list of the wall type with data in one set and the repeated set has no data.
It looks like the parameters I created are not shareable.
if (Convert.ToString(value) != "")
{
Type type = value.GetType();
string originalFile = uiApp.Application.SharedParametersFilename;
string tempFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) + ".txt";
using (File.Create(tempFile)) { }
uiApp.Application.SharedParametersFilename = tempFile;
try
{
if (ele.LookupParameter(param) == null)
{
ExternalDefinitionCreationOptions edco = null;
if (type.Name.Equals("Double"))
edco = new ExternalDefinitionCreationOptions(param, ParameterType.Number);
else
edco = new ExternalDefinitionCreationOptions(param, ParameterType.Text);
edco.Visible = true;
var definition = uiApp.Application.OpenSharedParameterFile().Groups.Create("Custom Parameters").Definitions.Create(edco);
var newCategorySet = uiApp.Application.Create.NewCategorySet();
newCategorySet.Insert(doc.Settings.Categories.get_Item(BuiltInCategory.OST_Walls));
Autodesk.Revit.DB.Binding binding = uiApp.Application.Create.NewTypeBinding(newCategorySet);
doc.ParameterBindings.Insert(definition, binding, BuiltInParameterGroup.PG_IDENTITY_DATA);
if (!string.IsNullOrEmpty((string)value))
ele.LookupParameter(param).Set((string)value);
}
else
{
if (!string.IsNullOrEmpty((string)value))
ele.LookupParameter(param).Set((string)
}
}
catch (Exception ex)
{
}
finally
{
uiApp.Application.SharedParametersFilename = originalFile;
}
}
Here, this block of code is executed in a loop where "element" is the element into whom the shared parameter needs to be added. "param" is the parameter name and "value" is the value for the parameter. Please let me know if this is the right way to create shared parameter that can be shared when project wall types are transferred to another project.
Thank you

definitely this will happen, as long as you are in a loop, and keeps creating a shared parameter for each file. this will lead to creating unique GUID for each revit file. and when you combine all you will find all the shared parameters with different Guids but with the same name.
you need to create the shared parameter once, then for each revit file, set the sharedparameter file (that is already created with sharedparameter) and get the sharedparameter from it, then assign it to the category you wish for each revit file.
moreinfo about shared parameters here
hope that helps.

Related

Solidworks C# can't extract item from feature that has TypeName equals "Reference"

i have opened solidworks assembly (swDocumentTypes_e.swDocASSEMBLY) using C# and i have iterated through all the features in order to get all the Sketchs called 'ISO/XXX' under each part of the assembly, here is the code
public void openFile(string skeletonFilePath)
{
object[] Features = null;
int i = 0;
string FeatType = null;[1]
string FeatTypeName = null;
if (string.IsNullOrWhiteSpace(skeletonFilePath)) { return; }
ModelDoc2 model = _sldWorks.OpenDoc("C:PATH/fileName.SLDASM", (int)swDocumentTypes_e.swDocASSEMBLY);
Feature swFeat = default(Feature);
SelectionMgr swSelMgr = default(SelectionMgr);
swSelMgr = (SelectionMgr)model.SelectionManager;
swFeat = (Feature)model.FirstFeature();
while ((swFeat != null))
{
FeatType = swFeat.Name;
FeatTypeName = swFeat.GetTypeName2();
if ((FeatTypeName == "Reference")
{
Debug.Print(" Name of feature: " + swFeat.Name);
Debug.Print(" Type of feature: " + swFeat.GetTypeName2());
}
swFeat = (Feature)swFeat.GetNextFeature();
}
}
the problem:
each time i try to extract the items under the feature (of one part) i got an exception, i have to tried these ways:
swFeat.GetDefinition() // i've got null exception
swFeat.GetSpecificFeature2() // i've got dynamic value which i don't know the class i need to cast with
var childs = (Object[])swFeatSupport.GetChildren(); // i've got only to constraints under the part
example of project
Your code is only iterating over top level features. You can use IFeature::GetFirstSubFeature() and IFeature::GetNextSubFeature to get sub feature. Make this function recursive so it will iterate over all features, regardless of how many levels deep they are. Another layer you need to consider is the components - you need to iterate over components in an assembly first if you need feature data in the context of individual parts.
Here's an example from the Solidworks API documentation. Its poorly written (IMO) but it will guide you in the right direction.

Visual Studio Debugger Extension get user settings

I'm writing a visual studio extension based on the Concord Samples Hello World project. The goal is to let the user filter out stack frames by setting a list of search strings. If any of the search strings are in a stack frame, it is omitted.
I've got the filter working for a hardcoded list. That needs to be in a non-package-based dll project in order for the debugger to pick it up. And I have a vsix project that references that dll with an OptionPageGrid to accept the list of strings. But I can't for the life of me find a way to connect them.
On the debugger side, my code looks something like this:
DkmStackWalkFrame[] IDkmCallStackFilter.FilterNextFrame(DkmStackContext stackContext, DkmStackWalkFrame input)
{
if (input == null) // null input frame indicates the end of the call stack. This sample does nothing on end-of-stack.
return null;
if (input.InstructionAddress == null) // error case
return new[] { input };
DkmWorkList workList = DkmWorkList.Create(null);
DkmLanguage language = input.Process.EngineSettings.GetLanguage(new DkmCompilerId());
DkmInspectionContext inspection = DkmInspectionContext.Create(stackContext.InspectionSession, input.RuntimeInstance, input.Thread, 1000,
DkmEvaluationFlags.None, DkmFuncEvalFlags.None, 10, language, null);
string frameName = "";
inspection.GetFrameName(workList, input, DkmVariableInfoFlags.None, result => GotFrameName(result, out frameName));
workList.Execute();
CallstackCollapserDataItem dataItem = CallstackCollapserDataItem.GetInstance(stackContext);
bool omitFrame = false;
foreach (string filterString in dataItem.FilterStrings)
{
if (frameName.Contains(filterString))
{
omitFrame = true;
}
}
The CallstackCollapserDataItem is where I theoretically need to retrieve the strings from user settings. But I don't have access to any services/packages in order to e.g. ask for WritableSettingsStore, like in You've Been Haacked's Example. Nor can I get my OptionPageGrid, like in the MSDN Options Example.
The other thing I tried was based on this StackOverflow question. I overrode the LoadSettingsFromStorage function of my OptionPageGrid and attempted to set a static variable on a public class in the dll project. But if that code existed in the LoadSettingsFromStorage function at all, the settings failed to load without even entering the function. Which felt like voodoo to me. Comment out the line that sets the variable, the breakpoint hits normally, the settings load normally. Restore it, and the function isn't even entered.
I'm at a loss. I really just want to pass a string into my Concord extension, and I really don't care how.
Ok, apparently all I needed to do was post the question here for me to figure out the last little pieces. In my CallstackCollapserDataItem : DkmDataItem class, I added the following code:
private CallstackCollapserDataItem()
{
string registryRoot = DkmGlobalSettings.RegistryRoot;
string propertyPath = "vsix\\CallstackCollapserOptionPageGrid";
string fullKey = "HKEY_CURRENT_USER\\" + registryRoot + "\\ApplicationPrivateSettings\\" + propertyPath;
string savedStringSetting = (string)Registry.GetValue(fullKey, "SearchStrings", "");
string semicolonSeparatedStrings = "";
// The setting resembles "1*System String*Foo;Bar"
if (savedStringSetting != null && savedStringSetting.Length > 0 && savedStringSetting.Split('*').Length == 3)
{
semicolonSeparatedStrings = savedStringSetting.Split('*')[2];
}
}
vsix is the assembly in which CallstackCollapserOptionPageGrid is a DialogPage, and SearchStrings is its public property that's saved out of the options menu.

Where to find my GUID on my c# solution

Hello I have been having issues with MonoGame when building I get the glbind... error in the opengl32.dll so I was suggested to find my GUID and it sounds like a simple task but i have looked in the project folder files and cant find it I found one which is
<ProjectGuid>{325BCA73-8459-49AF-9C31-D4A268BF8A1A}</ProjectGuid>
but im looking for one like this
<ProjectTypeGuids>{9B831FEF-F496-498F-9FE8-180DA5CB4258};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
here is a image of my file folder and the main "collisions".csproj file where I found the one GUID. I have done some research but i cant seem to find an answer as to where to look.
HERE
More accuretly im looking for the Projecttypeguids so I can delete one of them to see if that solves my problem as suggested here....I recognized what i worded at the top is kind of vague sorry
Here
The first example you gave is the GUID of your project. Hence ProjectGuid.
The second is a list of the GUIDs of the project types of your project. Hence ProjectTypeGuids.
If you are looking for the GUID of your project, the first example is giving you the correct answer.
The screenshot you linked to shows a project that does not have any type GUIDs listed. If present, the value is mostly used by development tools (e.g. VS uses it to figure out what items to include in the context menus for adding new items.) If there is no project type GUID your project will still "work" for the most part, but you will likely encounter odd behavior in your IDE of choice.
The project type GUID values in your question are correct for a project that is a C# application that uses the MonoGame plugin. If your project file is missing that tag, just add it yourself with whichever GUIDs you want your project to have.
(The list of well-known GUIDs can be found here, though the MonoGame one I had to look up on Google.)
First you didn't mentioned what you're using winforms or wpf.
OK whatever.The ProjectTypeGuids is not supported in winforms you can find them if you're using wpf.
If you're using wpf you can use this code:
public string GetProjectTypeGuids(EnvDTE.Project proj)
{
string projectTypeGuids = "";
object service = null;
Microsoft.VisualStudio.Shell.Interop.IVsSolution solution = null;
Microsoft.VisualStudio.Shell.Interop.IVsHierarchy hierarchy = null;
Microsoft.VisualStudio.Shell.Interop.IVsAggregatableProject aggregatableProject = null;
int result = 0;
service = GetService(proj.DTE, typeof(Microsoft.VisualStudio.Shell.Interop.IVsSolution));
solution = (Microsoft.VisualStudio.Shell.Interop.IVsSolution)service;
result = solution.GetProjectOfUniqueName(proj.UniqueName, hierarchy);
if (result == 0)
{
aggregatableProject = (Microsoft.VisualStudio.Shell.Interop.IVsAggregatableProject) hierarchy;
result = aggregatableProject.GetAggregateProjectTypeGuids(projectTypeGuids);
}
return projectTypeGuids;
}
public object GetService(object serviceProvider, System.Type type)
{
return GetService(serviceProvider, type.GUID);
}
public object GetService(object serviceProviderObject, System.Guid guid)
{
object service = null;
Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider = null;
IntPtr serviceIntPtr;
int hr = 0;
Guid SIDGuid;
Guid IIDGuid;
SIDGuid = guid;
IIDGuid = SIDGuid;
serviceProvider = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)serviceProviderObject;
hr = serviceProvider.QueryService(SIDGuid, IIDGuid, serviceIntPtr);
if (hr != 0)
{
System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr);
}
else if (!serviceIntPtr.Equals(IntPtr.Zero))
{
service = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(serviceIntPtr);
System.Runtime.InteropServices.Marshal.Release(serviceIntPtr);
}
return service;
}
it's from here

AccessViolationException when accessing the Above, Below, Suffix, and Prefix properties of a Dimension

In Revit 2013 I have tool that I'm making that copies dimensions from one drafting view to another. I've got it to properly create a new version of a dimension including the Curve, DimensionType, and References but I'm having trouble with the properties Above, Below, Prefix, and Suffix. They copy just fine if at least one of them has a value. However, if none of them have a value then it will throw an AccessViolationException when I try to access them. I have tried to catch that exception but it bubbles up and it crashes Revit (I'm assuming it's caused by native code that fails).
How can I check to see if these properties have any value when I do my copying without triggering this AccessViolationException?
Autodesk Discussion Group Question
The DimensionData class is my own used for storing the dimension information so that it can be used to create the dimension in a separate document.
private IEnumerable<DimensionData> GetDimensionDataSet(Document document,
View view)
{
if (document == null)
throw new ArgumentNullException("document");
if (view == null)
throw new ArgumentNullException("view");
List<DimensionData> dimensionDataSet = new List<DimensionData>();
FilteredElementCollector dimensionCollector =
new FilteredElementCollector(document, view.Id);
dimensionCollector.OfClass(typeof(Dimension));
foreach (Dimension oldDimension in dimensionCollector)
{
Line oldDimensionLine = (Line)oldDimension.Curve;
string dimensionTypeName = oldDimension.DimensionType.Name;
List<ElementId> oldReferences = new List<ElementId>();
foreach (Reference oldReference in oldDimension.References)
oldReferences.Add(oldReference.ElementId);
DimensionData dimensionData;
try
{
string prefix = oldDimension.Prefix;
dimensionData = new DimensionData(oldDimensionLine,
oldReferences,
dimensionTypeName,
prefix,
oldDimension.Suffix,
oldDimension.Above,
oldDimension.Below);
}
catch (AccessViolationException)
{
dimensionData = new DimensionData(oldDimensionLine,
oldReferences, dimensionTypeName);
}
dimensionDataSet.Add(dimensionData);
}
return dimensionDataSet;
}
Regarding transactions: As far as I'm aware, you are only required to be inside a transaction when you are making any sort of CHANGE (modifications, deletions, additions). If all you are doing is collecting dimension information, you would not need a transaction, but when you use that information to create new dimensions in another document, that code would have to be inside a transaction. I have had a number of programs under development which did not yet modify the document but simply collected parameter settings and posted them to a TaskDialog.Show(). These programs worked fine, and I don't see anything in your code that actually modifies your model, so that doesn't seem to be your issue.
It seems like I bug.
Can you post the issue to the ADN Support?
The solution I can suggest is to use Parameters of the Dimension element instead of Dimension class properties.
For example, you can get Suffix and Prefix by following code
var suffixParameter =
oldDimension.get_Parameter(BuiltInParameter.SPOT_SLOPE_SUFFIX);
string suffix = null;
if (suffixParameter != null)
{
suffix = suffixParameter.AsString();
}
var prefixParameter =
oldDimension.get_Parameter(BuiltInParameter.SPOT_SLOPE_PREFIX);
string prefix = null;
if (prefixParameter != null)
{
prefix = prefixParameter.AsString();
}
Unfortunatelly, I don't tell you how to get Above and Below Properties via parameters, because I don't have a project to test. But you can easily determine parameters using BuiltInParameter Checker
Hope it helps.

Unregistering datasource and deleting associated CSV file

I'm automating a mailmerge process which uses a CSV file. Part of this process requires creating a database (OpenOffice odb file) and then registering this as a datasource. When I come to delete the database I get an exception stating 'Cannot delete yourFile:It is being used by another person or program'. The problem is that I cannot get the OpenOffice process to release this resource (without killing it). My current code is:
public string DeleteDatasource(string datasourceName)
{
string result = string.Empty;
object databaseContext = _MultiServiceFactory.createInstance("com.sun.star.sdb.DatabaseContext");;
try
{
XDatabaseRegistrations databaseRegistrations = (XDatabaseRegistrations)databaseContext;
if(databaseRegistrations.hasRegisteredDatabase(datasourceName))
{
/* //attempt one
XNameAccess nameAccess = (XNameAccess)OODatabaseContext;
object datasource = nameAccess.getByName(datasourceName);
XNamingService namingservice = (XNamingService)OODatabaseContext;
namingservice.revokeObject(datasourceName);
*/
//attempt 2
string databaseLocation = databaseRegistrations.getDatabaseLocation(datasourceName);
databaseRegistrations.revokeDatabaseLocation(datasourceName);
if (!String.IsNullOrEmpty(databaseLocation))
try
{
//As File Path converts the uno file string into a standard form i.e. "file:///c:/temp/DatabaseFile.odb" to "c:\\temp\\DatabaseFile.odb"
File.Delete(databaseLocation.AsFilepath());
}
catch (System.Exception ex)
{
//some error handling
}
}
return result;
}
catch (System.Exception ex)
{
//More error handling
}
}
Any ideas how I can unregister this datasource such that I can then delete the odb.
Thanks
Managed to get around this issue and just in case anyone else is interested here's how.
The key was to get a reference to the actual datasource and to then dispose of this.
The basic steps are:
Check if a datasource exists with the specified name
Get datasource object
Get the datasource filename
Dispose of the database document associated with the datasource
Dispose the actual datasource
Delete the database file :)
The source code for this looks something like
XNameAccess nameAccess = (XNameAccess)_MultiServiceFactory.createInstance("com.sun.star.sdb.DatabaseContext");
object datasource = nameAccess.getByName(datasourceName);
XDocumentDataSource obj = (XDocumentDataSource)((Any)datasource).Value;
//get the location of the associated odb file before we dispose the document object
//and deregister the datasource
string databaseLocation = databaseRegistrations.getDatabaseLocation(datasourceName);
databaseRegistrations.revokeDatabaseLocation(datasourceName);
((XComponent)obj.DatabaseDocument).dispose();
((XComponent)obj).dispose();
//put in a try block as we want to continue even if this fails
//AsFilepath converts the OpenOffice file path to standard for that can be used with the standard IO file access classes
File.Delete(databaseLocation.AsFilepath());
If there are any improvements please let me know...
Click View,Click Data Sources,
Right Click Registered Databases you wanted to remove,
Click Registered Databases,
Click Delete for the highlighted registered database you want to remove.

Categories