My data is a list of groups, each having an undefined number of items. For the Hubpage I want to limit the items for each group to a specific number. Do I have to create a second collection with only those ten items or is there a XAML way to limit the group items to the top n?
If you're binding to an IEnumerable off of an ObservableCollection (or other Collection type), use the Take extension method to return the Top N. In the example template, you would do something like ...
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var sampleDataGroups = SampleDataSource.GetGroups((String)navigationParameter);
this.DefaultViewModel["Groups"] = sampleDataGroups.Take(5);
}
Both approaches are possible, but with the caveats. If you would like to use standard XAML controls you would have to effectively create a new collection with as many items as you would like to show. Take(N) for example would create new collection with N elements. You could also create your own custom control that will limit amount of visible elements. I general new collection approach is the most common one.
You can do the following in the 'Grouped' event of the grid:
if(xamDataGridHotworkS_Flow.FieldLayouts[0].SortedFields.Count > 1)
{
xamDataGridHotworkS_Flow.FieldLayouts[0].SortedFields.RemoveAt(1);
}
If there is grouping on the grid, remove the next grouping supplied by the user.
Related
I am looking for the simplest way to get the referenced item value for a droplink field.
#Html.Sitecore().Field("Alignment")
I want to get the value of the choice, what's the best approach?
If you need to have ability to edit fields of alignment item which is chosen in 'Alignment' droplink field of context item or just show values of alignment item's fields for visitors:
#{
Sitecore.Data.Fields.ReferenceField alignmentField = Sitecore.Context.Item.Fields["Alignment"];
Sitecore.Data.Items.Item alignmentItem = alignmentField.TargetItem;
}
<div>
#Html.Sitecore().Field("Text of Alignment", alignmentItem)
</div>
This example assumes that Alignment template contains 'Text of Alignment' field.
The Droplink field stores the referenced item's ID. To retrieve this ID (providing the field is present in your current item/model):
((LinkField)Model.Item.Fields["Alignment"]).Value
To output the referenced item's name, you could do something like this:
#(Model.Item.Database.GetItem(((LinkField)Model.Item.Fields["Alignment"]).Value).Name)
But that's really ugly. The preferred approach would be to create an extension method encapsulating some of the above so you're not having to re-type that out :D
The article Extending the SitecoreHelper Class by John West shows how to extend the SitecoreHelper class to add custom field renderers, so you could end up creating a neat re-usable snippet like:
#(Html.Sitecore().ReferenceField("Alignment","Name"))
If this is in a partial view i.e. .cshtml file you can also use something like below:
Sitecore.Data.Fields.TextField alignment= Model.Item.Fields["Alignment"];
This will give you the id of the set item in the drop link , then from that id can retrieve it from the database like:
#if (!string.IsNullOrWhiteSpace(alignment.Value))
{
var setAlignment = Sitecore.Context.Database.GetItem(alignment.Value);
if (setAlignment != null && !string.IsNullOrWhiteSpace(setAlignment.Name))
{
setAlignment.Name
}
}
Personally i prefer this way as i can check if the droplink is set before trying to use the value.
I have a document in RavenDB that looks looks like:
{
"ItemId": 1,
"Title": "Villa
}
With the following metadata:
Raven-Clr-Type: MyNamespace.Item, MyNamespace
Raven-Entity-Name: Doelkaarten
So I serialized with a type MyNamespace.Item, but gave it my own Raven-Entity-Name, so it get its own collection.
In my code I define an index:
public class DoelkaartenIndex : AbstractIndexCreationTask<Item>
{
public DoelkaartenIndex()
{
// MetadataFor(doc)["Raven-Entity-Name"].ToString() == "Doelkaarten"
Map = items => from item in items
where MetadataFor(item)["Raven-Entity-Name"].ToString() == "Doelkaarten"
select new {Id = item.ItemId, Name = item.Title};
}
}
In the Index it is translated in the "Maps" field to:
docs.Items
.Where(item => item["#metadata"]["Raven-Entity-Name"].ToString() == "Doelkaarten")
.Select(item => new {Id = item.ItemId, Name = item.Title})
A query on the index never gives results.
If the Maps field is manually changed to the code below it works...
from doc in docs
where doc["#metadata"]["Raven-Entity-Name"] == "Doelkaarten"
select new { Id = doc.ItemId, Name=doc.Title };
How is it possible to define in code the index that gives the required result?
RavenDB used: RavenHQ, Build #961
UPDATE:
What I'm doing is the following: I want to use SharePoint as a CMS, and use RavenDB as a ready-only replication of the SharePoint list data. I created a tool to sync from SharePoint lists to RavenDB. I have a generic type Item that I create from a SharePoint list item and that I serialize into RavenDB. So all my docs are of type Item. But they come from different lists with different properties, so I want to be able to differentiate. You propose to differentiate on an additional property, this would perfectly work. But then I will see all list items from all lists in one big Items collection... What would you think to be the best approach to this problem? Or just live with it? I want to use the indexes to create projections from all data in an Item to the actual data that I need.
You can't easily change the name of a collection this way. The server-side will use the Raven-Entity-Name metadata, but the client side will determine the collection name via the conventions registered with the document store. The default convention being to use the type name of the entity.
You can provide your own custom convention by assigning a new function to DocumentStore.Conventions.FindTypeTagName - but it would probably be cumbersome to do that for every entity. You could create a custom attribute to apply to your entities and then write the function to look for and understand that attribute.
Really the simplest way is just to call your entity Doelkaarten instead of Item.
Regarding why the change in indexing works - it's not because of the switch in linq syntax. It's because you said from doc in docs instead of from doc in docs.Items. You probably could have done from doc in docs.Doelkaartens instead of using the where clause. They are equivalent. See this page in the docs for further examples.
Let's say I have database with two tables - Groups and Items.
Table Groups has only two columns: Id and Name.
Table Items has three columns: Id, GroupId and Name.
As you can see, there is one-to-many relation between Groups and Items.
I'm trying to build a web service using WCF and LINQ. I've added new LINQ to SQL classes file, and I've imported these two tables. Visual Studio has automatically generated proper classes for me.
After that, I've create simple client for the service, just to check if everything is working. After I call GetAllGroups() method, I get all groups from Groups table. But their property Items is always null.
So my question is - is there a way to force WCF to return whole class (whole Group class and all Items that belong to it)? Or is this the way it should behave?
EDIT: This is function inside WCF Service that returns all Groups:
public List<Group> GetAllGroups()
{
List<Group> groups = (from r in db.Groups select r).ToList();
return groups;
}
I've checked while debugging and every Group object inside GetAllGroups() function has it's items, but after client receives them - every Items property is set to null.
Most likely, you're experiencing the default "lazy-loading" behavior of Linq-to-SQL. When you debug and look at the .Items collection - that causes the items to be loaded. This doesn't happen however when your service code runs normally.
You can however enforce "eager-loading" of those items - try something like this:
(see Using DataLoadOptions to Control Deferred Loading or LINQ to SQL, Lazy Loading and Prefetching for more details)
public List<Group> GetAllGroups()
{
// this line should really be where you *instantiate* your "db" context!
db.DeferredLoadingEnabled = false;
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Group>(g => g.Items);
db.LoadOptions = dlo;
List<Group> groups = (from r in db.Groups select r).ToList();
return groups;
}
Do you get the Items collection populated now, when you call your service?
This will probably be a basic questions for the LINQ & architecture experts however I am failing to understand a problem i've encounted when trying to update a 'Static ObservableCollection.
Me.Grid1.ItemsSource = ContactList
Me.Grid2.ItemsSource = From s In ContactList Where s.ContactTypes.Any(Function(t) t.ContactTypeName = "Christmas List")
If I add a new Contact with the ContactType "Christmas List" to the ContactList ObservableCollection, Grid1 reflects the additional Contact however Grid2 does not reflect the change unless I rebind.
Anyway to Reflect the change in Grid2 to show the new Contact with the queried ContactType
Grid2 is actually binding to an IEnumerable(Of Contact) instead of an Observable Collection. That's why the change isn't reflected in Grid2. You need to cause your Linq query to reexecute using an event or INotifyPropertyChanged.
It could be happening due to the deferred execution nature of LINQ query. The values are fetched only when, you start enumerating over the result set. That is why, you have to rebind the data source, to see the change. Try adding ToList(), method at the end of the query. For e.g.
Me.Grid2.ItemsSource = From s In ContactList Where s.ContactTypes.Any(Function(t) t.ContactTypeName = "Christmas List").ToList();
You need my ObservableComputations library. Using this library you can code like this:
Me.Grid2.ItemsSource = ContactList.Filtering(c => c.ContactTypes.ContainsComputing("Christmas List").Value);
Filtering extention method returns instance of ObservableCollection and reflects all the changes in the ContactList collection and ContactTypes collection. Writing the code above, I assumed contactContactTypes id ObservableCollection. If this is not so, then you can code:
Me.Grid2.ItemsSource = ContactList.Filtering(c => c.ContactTypes.Contains("Christmas List"));
In this case do not forget to add the implementation of the INotifyPropertyChanged interface to Contact class, so that the result ObservableCollection reflects the change of contact.ContactTypes property.
I have an observable collection that is exposed to the user by a collectionviewsource. One of the properties on the items in the collection is sortorder. I am trying to allow the user to permanently resort this collection and propagate the changes to the db.
I have the CVS working where I can resort the individual items as they are displayed in the listbox. Now however I have to change the item.sortorder==cvs.currentindex and i am having trouble figuring out the proper way to do this.
EDIT
evidently I was not clear enough. Sortorder is a field in my DB that is part of my object that allows the user to control position of the items as displayed in list controls. I am trying to give my user the ability to change how these items are sorted in the future by changing the value of the sortorder field to equal the current index of the displayed item.
items current sortorder value is 3.
user moves displayed listitem to position 0(ie first position)
items new sortorder=0 item with original sortorder will become 1 etc
this would be achieved by looping through the sorted CVS and making Item.SortOrder= CVS.Item.index
Databases return rows from table based typically on the order they were added to the table unless you specify an order by clause in your query. changing the order in the database is not a good idea. instead, try something such as using a parameterized query and passing in the column and direction you wish to be sorted which is retrieved from a user preference.
I figured it out.
I went back and looked at the code that I was using to change the position of the elements and I am actually using the collection itself:
private void OnDecreaseSortOrderCommandExecute()
{
int index = QuestionsCVS.View.CurrentPosition;
QuestionsViewModel item = SelectedQuestionVM;
if (item != null && index > 0)
{
SortableQuestionsVMCollection.RemoveAt(index);
SortableQuestionsVMCollection.Insert(index - 1, item);
QuestionsCVS.View.Refresh();
QuestionsCVS.View.MoveCurrentTo(item);
}
}
So I simply did this:
private void ResortSortableQuestionsVMCollection()
{
for (int i = 0; i < SortableQuestionsVMCollection.Count; i++)
{
SortableQuestionsVMCollection[i].SortOrder = i;
}
}
I dont know if this will work in every circumstance but it certainly did what I wanted for this one.