Getting Active View Object Parameters? - revit-api

I am new to the API and I'm trying to get values from the active view. I am using the following code as a mock up to what I'm trying to do:
public void GetViewProperties()
{
String viewname;
String typename;
String levelname;
String Output;
ViewFamilyType VfamType;
Level lev;
//Get document and current view
Document doc = this.ActiveUIDocument.Document;
View currentView = this.ActiveUIDocument.ActiveView;
//Find the view family type that matches the active view
VfamType = new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
.Where(q => q.Name == "1-0-Model").First() as ViewFamilyType;
//Find the level that matches the active view
lev = new FilteredElementCollector(doc).OfClass(typeof(Level))
.Where(q => q.Name == "00").First() as Level;
//Get the view's current name
viewname = currentView.Name.ToString();
//Get the name of the view family type
typename = VfamType.Name;
//Get the name of the level
levelname = lev.Name.ToString();
//Combine results for task dialog
Output = "View: " + viewname + "\n" + typename + "-" + levelname;
//Show results
TaskDialog.Show("View Properties Test",Output);
}
I'm cheating at the moment by grabbing the view type and level by name. I really want them to be found by looking at the properties of the active view. I can't figure out how I am meant to access the view type and level name properties. I need to make lambda use a variable e.g. (q => q.Name == Level.name), (q => q.Name == ViewFamilyType.name).
Thanks in advance!

Here is your code corrected:
public void GetViewProperties()
{
//Get document and current view
Document doc = this.ActiveUIDocument.Document;
View currentView = this.ActiveUIDocument.ActiveView;
//Find the view family type that matches the active view
var VfamType = (ViewFamilyType)doc.GetElement(currentView.GetTypeId());
//Find the level that matches the active view
Level lev = currentView.GenLevel;
//Get the view's current name
string viewname = currentView.Name;
//Get the name of the view family type
string typename = VfamType.Name;
//Get the name of the level
string levelname = lev.Name;
//Combine results for task dialog
string Output = "View: " + viewname + "\n" + typename + "-" + levelname;
//Show results
TaskDialog.Show("View Properties Test", Output);
}
You don't need to use a FilteredElementCollector to get these informations. And if you need elsewhere, you don't need a Where: just put your lambda in the First:
new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
.First(q => q.Name == "1-0-Model")
If you need to access in your lambda a property specific to a class, not defined on Element, you can use Cast:
new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
.Cast<ViewFamilyType>().First(vft => vft.IsValidDefaultTemplate)
And please do not declare all your variable at the start of your methods. You're not writing Pascal. Declare variables as close to the first spot that you use them as possible. It makes your code much more readable. The closer a variable is declared to where it is used, the less scrolling/searching you have to do when reading the code later and it also naturally narrow their scope.

You're probably looking for View.GenLevel property. This will work for views related to levels, such as Plan Views. Note that if this View is not generated by a level, this property is null.

Related

Filter out users in a drop down on PCF

In ClaimCenter I am trying to filter a drop down list to only display users that have a certain role. I am using a User input cell. There is no value range on the userinput cell only value. The value is set the user that they select so right now it's displaying all the users in the system instead of just the ones with the role that i want. Is there a way to show just the users that have the "Adjuster" role. I don't see a filter option either on this cell.
Right click the element and select "Change Element Type"
Then select "Range Input".
Then in the ValueRange property add a call to the code that you write.
The code to should find the subset of users that you want to show in the drop down and return them as a List or User[], something like this might work
function myValueRangeFunction(pClaim: Claim) : User[] {
//gets the group from the DB by public ID
var adjusterGroup = Group ("cc:123");
var adjustersOnly = new Set<User>();
var groupUsers = adjusterGroup.MembersNoSystemUsers
adjustersOnly.addAll(groupUsers*.Users)
return adjustersOnly.toArray()
}
You need to change the input type to Range Input (or Range Cell in case you are using List View) where valueRange property calls a method which retrieves users with a specific role.
.pcf file:
<RangeInput
editable="true"
id="userInput"
label=""Adjusters""
value="claim.AssignedUser"
valueRange="UserRoleUtil_Ext.Adjusters"
valueType="entity.User"/>
UserRoleUtil_Ext.gs:
uses gw.api.database.Query
uses gw.api.database.Relop
class UserRoleUtil_Ext {
public static property get Adjusters() : User[] {
var adjusterRole = Query.make(Role).compare(Role#Name, Relop.Equals, "Adjuster").select().AtMostOneRow
// Alternatively, you can retrieve the Role by its public-id, e.g.:
// var roleRetrievedById = Query.make(Role).compare(Role#PublicID, Relop.Equals, "cc:1").select().AtMostOneRow
return adjusterRole.AllUsersArray
}
}

ExpandoObject - why a Type behaves differently?

One for the gurus, please convince me/us what is going on.
List<ExpandoObject> peopleList = new List<ExpandoObject>();
dynamic expandoObj1 = new ExpandoObject();
expandoObj1.id = 1;
expandoObj1.first = "fred";
expandoObj1.last = "krugger";
peopleList.Add(expandoObj1);
dynamic expandoObj2 = new ExpandoObject();
expandoObj2.id = 2;
expandoObj2.first = "george";
expandoObj2.last = "benson";
peopleList.Add(expandoObj2);
//test access the props
var expObj = expandoObj1;
var name = expObj.first;
var expObj2 = peopleList[0] as dynamic;
var name2 = expObj2.first;
IDictionary<string, object> expObj3 = peopleList[0] as ExpandoObject;
var name3 = expObj3["first"];
var expObj4 = peopleList[0] as ExpandoObject;
//var name4 = expObj4.first; //THIS DOESN'T WORK - ExpandoObject does not contain a definition for 'first' etc...
In all cases, the LEFT-HAND SIDE is a System.Dynamic.ExpandoObject;
Why then, on the 4th case expObj4, i cannot access the property expObj4.first ?
ExpandoObject is a sealed class which stores data in a dictionary. It implements IDynamicMetaObjectProvider interface which provides dynamic behaviour to the classes implementing it. It also implements IDictionary interface which provides dictionary like behaviour to it. It is supposed to be checked and validated at compile time.
dynamic is a type which is not supposed to be checked by the compiler at compile time. It is checked and breaks at runtime. At compile time, a dynamic entity is assumed to support any operation. So, when you say, it is a expandoobject, the field called first does not get appended to object itself.
Check source code of expando object here
https://github.com/Microsoft/referencesource/blob/master/System.Core/Microsoft/Scripting/Actions/ExpandoObject.cs
Think of dynamic behavior like an object. You can put any type there. When you are adding to list, you are adding to list as dynamic, but the inherent type of item being added is ExpandoObject. So, you are able to cast it back to ExpandoObject.
When you say,
expandoObj1.first = "fred";
it is same as saying,
expandoObj1.Add("first", "fred");
When you used
var expObj = expandoObj1;
var name = expObj.first;
you were using expandoObject in dynamic form. So, you were able to access properties directly. When you cast it to ExpandoObject class, you were using actual ExpandoObject class which stores fields in Dictionary, so dot(.) notation does not work.
var expObj4 = peopleList[0] as ExpandoObject;
variable on left hand side is still ExpandoObject, not a dictionary. ExpandoObject exposes its members through collection search.
var name4 = expObj4.Where(t=>t.Key == "first").First().Value;
When you cast it to a dictionary, it works like a dictionary.
IDictionary<string, object> expObj3 = peopleList[0] as ExpandoObject;
var name3 = expObj3["first"];
When you cast it to a dynamic, you can access these keys like they are properties of the class.
Further reference
Dynamically adding properties to an ExpandoObject
This is because the variable expObj4 is declared as ExpandoObject and not as dynamic. This is an important difference.
Try this:
dynamic a = new ExpandoObject();
a.Name = "Test";
This compiles, but the following doesn't:
ExpandoObject a = new ExpandoObject();
a.Name = "Test";
you get this:
CS1061 'ExpandoObject' does not contain a definition for 'Name' and no extension method 'Name' accepting a first argument of type 'ExpandoObject' could be found
The variables you have that are related to this are:
expandoObj1 - dynamic
expandoObj2 - dynamic
expObj1 - dynamic
expObj2 - dynamic
expObj3 - dictionary, but you use dictionary access here, not dot-access
The magic "let's see if we can access the thing at runtime" code of the compiler only kicks in if the expression or variable is dynamic. ExpandoObject is just a type that supports this.

Value does not fall within the expected range - Exception for SharePoint Lookup Field

I am trying to copy data from one list to other list (both lists are on different sites) along with lookup columns. But, I am getting an error for lookup field as:
Value does not fall within the expected range
Code works and data gets copied for other non-lookup fields. I tried every possible way including increasing List View Lookup Threshold and all possible ways of code but still error persists at ExecuteQuery().
Below is my code for lookup field:
if (field is FieldLookup && field.InternalName == "Country")
{
var CountryLookup = (item.FieldValues["Country"] as FieldLookupValue).LookupValue.ToString();
var CountryLookupId = (item.FieldValues["Country"] as FieldLookupValue).LookupId.ToString();
FieldLookupValue flvRDS = new FieldLookupValue();
flvRDS.LookupId = int.Parse(CountryLookupId);
itemToCreate["Country"] = flvRDS;
itemToCreate.Update();
destContext.ExecuteQuery();
}
Help is really appreciated.
I assume item is the new ListItem you're trying to create on your target list.
But you're never in fact reading any value from field here! So basically, you're trying to set your new FieldLookup.LookupId with the item["Country"].LookupId, which should logically be empty at this moment.
Here's a method I use to retrieve a lookup field ListItem from a value, feel free to modify it to fit your need, since I don't know how you want to retrieve it (SPList is an alias for Microsoft.SharePoint.Client.List).
private ListItem GetLookupItem(FieldLookup lookupField, string lookupValue)
{
string mappingField = lookupField.LookupField;
Microsoft.SharePoint.Client.List lookupList = Context.Web.Lists.GetById(new Guid(lookupField.LookupList));
Context.Load(lookupList);
Context.ExecuteQuery();
ListItemCollection libListItems = lookupList.GetItems(CamlQuery.CreateAllItemsQuery());
Context.Load(libListItems, items => items.Include(
itemlookup => itemlookup.Id,
itemlookup => itemlookup[mappingField]));
Context.ExecuteQuery();
foreach (ListItem mappedItem in libListItems)
{
object mappedField = mappedItem[mappingField];
if (mappedField != null && mappedField.ToString().Equals(lookupValue))
return mappedItem;
}
return null;
}
Now that you have the corresponding ListItem, you can set your item.LookupId with its Id:
if (field is FieldLookup && field.InternalName == "Country")
{
FieldLookupValue flvRDS = new FieldLookupValue();
flvRDS.LookupId = GetLookupItem(field as FieldLookup, "France").Id; // here, dunno how you get your country's name
itemToCreate["Country"] = flvRDS;
itemToCreate.Update();
destContext.ExecuteQuery();
}
Feel free to add some more previous code if you want an answer more suited for your specific issue.

create a filter not a group filter

I am creating a custom module in Orchard , I would like to create a query programmatically.
string queryName= "Product";
var item = _orchardServices.ContentManager.New("Query");
item.As<TitlePart>().Title =queryName;
_orchardServices.ContentManager.Create(item, VersionOptions.Draft);
if (!item.Has<IPublishingControlAspect>() && !item.TypeDefinition.Settings.GetModel<ContentTypeSettings>().Draftable)
_orchardServices.ContentManager.Publish(item);
var queryPart = item.As<QueryPart>();
queryPart.ContentItem.ContentType = queryName;
string desc =" filter for the query";
string contentType = "CommonPart.ChannelID.";
var filterGroupRecord = new FilterGroupRecord();
var filterRecord = new FilterRecord()
{
Category = "CommonPartContentFields",
Type = contentType,
Position = 0,
};
filterRecord.State = "<Form><Description>" + desc + "</Description><Operator>Equals</Operator><Value>ChannelId</Value></Form>";
filterGroupRecord.Filters.Add(filterRecord);
queryPart.FilterGroups.Insert(0, filterGroupRecord);
the problem is that:I want set a filters of the query,not a filters group.
could you tell me how to improve my code?
Database structure and class declarations make it impossible. Why do you need it?
Update:
I means that you must use FilterGroupRecord at least one.
But when Query published that Filter Group will be created automatically if query have not yet Filter Group (see at QueryPartHandler). You should add your filters to this group. And not needed to create new group.
var existingFilterGroup = queryPart.FilterGroups[0];
existingFilterGroup.Filters.Add(filterRecord);
Update 2:
To avoid problems with draftable query (and several other potential problems Orchard CMS: Adding default data to fields and then querying them) it is better to move the calling Publish method to the end of your code and other part of your code should be left unchanged. And in your case would be better if you will always publish your query without checking IPublishingControlAspect and Draftable.

Subsonic 3 - Sequence contains no matching element

I need help creating a LINQ SQL with subsonic. First the basics, this works fine:
var query = (from o in bd.concelhos
orderby o.descricao
select o);
var results = query.ToList<concelhos>();
However, I want to filter out some columns and I have created the following code:
var query = (from o in bd.concelhos
orderby o.descricao
select new FilteredConcelhos { id = o.idDistrito + "/" + o.idConcelho, descricao = o.descricao });
var results = query.ToList<FilteredConcelhos>();
which errors out in the ToList method with the description "Sequence contains no matching element"
Any help would be great with this...
update:
Turns out I was missing get set attributes in the newly declared class...
Like so
public class FilteredConcelhos
{
public string id { get; set; }
public string descricao { get; set; }
}
This clears the exception, but the resulting List is still all wrong (FilteredConcelhos.id contains nothing and FilteredConcelhos.descricao contains numbers)
Can you try to first execute the ToList and the select afterwards - then the select is performed via linq 2 objects!
Have you tried to work with an anonymous type?
var query = (from o in bd.concelhos
orderby o.descricao
select new { id = o.idDistrito + "/" + o.idConcelho,
descricao = o.descricao });
var results = query.ToList();
Unfortunately, this happened to me a lot. I'm not sure about the details of how Linq 2 Object works, but if you'll call ToList on the original object, like this:
from o in bd.concelhos.ToList()
...
It should do the trick.

Resources