Hi
Take a look at the filter event of the PageList. I would create a custom filter that randomizes the pages.
I've written a little about it:
I've looked at it and must say that it didn't make me any wiser. I can see how I can use it to filter out things but not randomize the order of the pages it containes.
Filter is not a very good name for what you can do with it. Think of filters more of a way to manipulate your PageDataCollection in any way you like. Remove pages, add pages, sort them, randomize, add properties to them etc.
If you take a look at my sample, you'll see that in the Filter method you have access to the whole PageDataCollection. Now you only need to loop through them and randomize :).
I actually found this code http://world.episerver.com/Templates/Forum/Pages/Thread.aspx?id=13161&epslanguage=en/ showing how it's done but what I can't seem to get the hang of is how to get the content of my PageList into a PageDataCollection. Or am I not getting the picture here? :)
No worries, we are all here to learn! Lets see, with PageList do you mean PageList.ascx (from the Public Templates) or PageList the EPiServer web control?
I actually edited my last response while you wrote your answer... :)
I'm using a modified version of the ascx-file from the Public Templates.
Something like this.
protected override void OnLoad(EventArgs e) { base.OnLoad(e); ... epiPageList.Filter += this.epiPageList_Filter; ... } protected void epiPageList_Filter(object sender, FilterEventArgs e) { new FilterRandomPages().Filter(e.Pages); }
That's it! Now I get it. Actually learned something toady, too. :) Thanks!
Regarding the link to the randomscript I posted earlier; Is it just me or is that not very random? More like scrolling.
Looks okay, but personally I prefer Linq for this :).
public static IEnumerable Randomize(this IEnumerable source) { Random rnd = new Random(); return source.OrderBy((item) => rnd.Next()); }Now you can just do myPageDataCollection.Randomize();
Hi Peter
For some reason the PageDataCollection wasn't to found of the OrderBy extension method. I used the Sort method instead.
using System; using System.Collections.Generic; using EPiServer.Core; using EPiServer.Filters; namespace FV.Templates.FV.Filters { public class FilterRandomize : IPageFilter { public void Filter(PageDataCollection pages) { pages.Sort(new FilterRandomizeSort()); } public void Filter(object sender, FilterEventArgs e) { this.Filter(e.Pages); } public bool ShouldFilter(PageData page) { throw new NotImplementedException(); } } public class FilterRandomizeSort : IComparer { public int Compare(PageData page1, PageData page2) { return new Random().Next(); } } }
I feel like I'm getting a little water over my head here. When I try to implement that code I get: "Using the generic type 'System.Collections.Generic.IComparer<T>' requires '1' type arguments" on row "public class FilterRandomizeSort : IComparer".
Right now it looks excactly the same as the code you posted besides from the namespace.
Sorry, client meeting.. I see the mistake now:
public class FilterRandomizeSort : IComparer
Should be:
public class FilterRandomizeSort : IComparer<PageData>
For some reason the syntax highlighter removed <PageData> when I added the code..
What I wanted to use this for was to randomize the order of a commercial banner listing in the right hand of the page. With the code you've so kindly composed here they randomize, but only ones. If I reload the page they remain in the same order. With the other code that I linked to further up they reorder them self every time the page is reloaded but with the downside that a couple of them nearly always to end up in the same position.
The code you mentioned where I was able to use Linq, how is this implemented? It may sound strange but I've still got a problem with some of the items almost always showing up in the same place in the order. Here's my class so far.
public class FilterRandomize : IPageFilter
{
public void Filter(PageDataCollection pages)
{
for (int i = 0; i < pages.Count; i++)
{
PageData x = pages[i];
Random rng = new Random();
int index = rng.Next(pages.Count - i) + i;
pages[i] = pages[index];
pages[index] = x;
}
}
public void Filter(object sender, FilterEventArgs e)
{
this.Filter(e.Pages);
}
public bool ShouldFilter(PageData page)
{
throw new NotImplementedException();
}
}
I think initializing the Random class inside a loop is a bad idé, it might get the same seed many times.
Try instantiation of the random object before the loop instead of inside.
@Frederik Vig 'For some reason the PageDataCollection wasn't to found of the OrderBy extension method'
> Import the Extension's with using directive
using System.Linq.Expressions;
and you're good to go.
Order by Guid
Using the neat trick of ordering by a Guid
yields the same distribution spread as the Fisher-Yates Shuffle Algorithm. The distribution spread is the ratio of the possible outcomes to the actual permutations (how many possible combinations exists versus how many the random sort can make)
For more info se the following link :http://blog.linqexchange.com/index.php/how-to-randomly-reorder-a-list-with-linq/
Armed with OrderBy Extensions and the order by Guid-trick
I propose the following solution:
//Hook up the event
yourOwn_PageList.Filter += new FilterEventHandler(YourOwn_PageList_Filter);
//Sort / filter in a random fashion
void YourOwn_PageList_Filter(object sender, EPiServer.Filters.FilterEventArgs e)
{
var pages = e.Pages.OrderBy(p => Guid.NewGuid()).ToArray();
for (int i = 0; i < pages.Length; i++)
e.Pages[i] = pages[i];
}
Hi,
I've got a PageList and I'd like to randomize the order of it. Is this done through a ForEach of some kind or is there a simpler way?
Best regards,