2009-10-12 13 views
0

J'essaie d'obtenir une image de fond choisie au hasard (à partir d'une sélection de 4 images) pour apparaître comme image de fond pour un panneau asp.net.Image d'arrière-plan aléatoire sur DIV

Le problème que j'ai est que le code fonctionne en passant par le code en mode débogage. Une fois que vous exécutez le code sur le site sans débogage, toutes les images sont les mêmes. C'est presque comme si le nombre aléatoire ne se faisait pas ramasser assez rapidement.

L'usercontrol est à l'intérieur d'un datalist.

Le usercontrol est la suivante:

<asp:Panel ID="productPanel" CssClass="ProductItem" runat="server"> 

<div class="title" visible="false"> 
    <asp:HyperLink ID="hlProduct" runat="server" /> 
</div> 
<div class="picture"> 
    <asp:HyperLink ID="hlImageLink" runat="server" /> 
</div> 
<div class="description" visible="false"> 
    <asp:Literal runat="server" ID="lShortDescription"></asp:Literal> 
</div> 
<div class="addInfo" visible="false"> 
    <div class="prices"> 
     <asp:Label ID="lblOldPrice" runat="server" CssClass="oldproductPrice" /> 
     <br /> 
     <asp:Label ID="lblPrice" runat="server" CssClass="productPrice" /></div> 
    <div class="buttons"> 
     <asp:Button runat="server" ID="btnProductDetails" OnCommand="btnProductDetails_Click" 
      Text="Details" ValidationGroup="ProductDetails" CommandArgument='<%# Eval("ProductID") %>' 
      SkinID="ProductGridProductDetailButton" /><br /> 
     <asp:Button runat="server" ID="btnAddToCart" OnCommand="btnAddToCart_Click" Text="Add to cart" 
      ValidationGroup="ProductDetails" CommandArgument='<%# Eval("ProductID") %>' SkinID="ProductGridAddToCartButton" /> 
    </div> 
</div> 

et le code est derrière ceci:

protected void Page_Load(object sender, EventArgs e) 
    { 

      // Some code here to generate a random number between 0 & 3 
      System.Random RandNum = new System.Random(); 
      int myInt = RandNum.Next(4); 

      if (productPanel.BackImageUrl != null) 
      { 
       switch (myInt) 
       { 
        case 0: 
         productPanel.BackImageUrl = "../App_Themes/emmaharris/images/frame1.gif"; 
         break; 
        case 1: 
         productPanel.BackImageUrl = "../App_Themes/emmaharris/images/frame2.gif"; 
         break; 
        case 2: 
         productPanel.BackImageUrl = "../App_Themes/emmaharris/images/frame3.gif"; 
         break; 
        case 3: 
         productPanel.BackImageUrl = "../App_Themes/emmaharris/images/frame4.gif"; 
         break; 
       } 

      } 
      // End of new code to switch background images 

    } 

T

Répondre

1

Parfois, au hasard est pas vraiment au hasard ...

Jon Skeet a un bon article sur le sujet: Why am I getting the same numbers out of Random time and time again?

Pour citer directement ce que Jon m'a dit une fois:

Un générateur de nombres pseudo-aléatoires (comme System.Random) n'est pas réellement aléatoire - il produira toujours la même séquence de résultats lors de l'initialisation avec le même dat une. Les données utilisées pour l'initialisation sont un numéro appelé graine.

Le problème de base est que lorsque vous créez une nouvelle instance de hasard en utilisant le constructeur parameterless (comme que nous faisons ici), il utilise une graine prise de « l'heure actuelle ». L'idée de l'ordinateur de « l'heure actuelle » peut ne changer une fois tous les 15ms (qui est une éternité en informatique) - donc si vous créez plusieurs nouvelles instances de au hasard dans une succession rapide, ils tous ont la même graine .

Qu'est-ce que vous voulez habituellement (en supposant ne se soucient pas d'être en mesure de reproduire résultats exacts, et vous ne besoin d'un générateur de nombres aléatoire sécurisé) est d'avoir un seul aléatoire utilisé tout au long de votre programme, a été initialisé la première fois qu'il est utilisé. Cela semble que vous pourriez simplement utiliser un champ statique quelque part (exposé comme propriété ) - fondamentalement un singleton. Malheureusement System.Random n'est pas thread-safe - si vous l'appelez de deux threads différents, vous pourriez obtenir problèmes (y compris obtenir la même séquence de nombres dans les deux threads).

C'est pourquoi j'ai créé StaticRandom dans ma petite boîte à outils des services publics - il est essentiellement un moyen de thread-safe d'obtenir nombres aléatoires, en utilisant une seule instance de aléatoire et un verrou. Voir http://www.yoda.arachsys.com/csharp/miscutil/usage/staticrandom.html pour un exemple rapide, et http://pobox.com/~skeet/csharp/miscutil pour la bibliothèque elle-même.

Divers Utilitaire générateur aléatoire de Jon Skeet

using System; 

namespace MiscUtil 
{ 
    /// <summary> 
    /// Thread-safe equivalent of System.Random, using just static methods. 
    /// If all you want is a source of random numbers, this is an easy class to 
    /// use. If you need to specify your own seeds (eg for reproducible sequences 
    /// of numbers), use System.Random. 
    /// </summary> 
    public static class StaticRandom 
    { 
     static Random random = new Random(); 
     static object myLock = new object(); 

     /// <summary> 
     /// Returns a nonnegative random number. 
     /// </summary>  
     /// <returns>A 32-bit signed integer greater than or equal to zero and less than Int32.MaxValue.</returns> 
     public static int Next() 
     { 
      lock (myLock) 
      { 
       return random.Next(); 
      } 
     } 

     /// <summary> 
     /// Returns a nonnegative random number less than the specified maximum. 
     /// </summary> 
     /// <returns> 
     /// A 32-bit signed integer greater than or equal to zero, and less than maxValue; 
     /// that is, the range of return values includes zero but not maxValue. 
     /// </returns> 
     /// <exception cref="ArgumentOutOfRangeException">maxValue is less than zero.</exception> 
     public static int Next(int max) 
     { 
      lock (myLock) 
      { 
       return random.Next(max); 
      } 
     } 

     /// <summary> 
     /// Returns a random number within a specified range. 
     /// </summary> 
     /// <param name="min">The inclusive lower bound of the random number returned. </param> 
     /// <param name="max"> 
     /// The exclusive upper bound of the random number returned. 
     /// maxValue must be greater than or equal to minValue. 
     /// </param> 
     /// <returns> 
     /// A 32-bit signed integer greater than or equal to minValue and less than maxValue; 
     /// that is, the range of return values includes minValue but not maxValue. 
     /// If minValue equals maxValue, minValue is returned. 
     /// </returns> 
     /// <exception cref="ArgumentOutOfRangeException">minValue is greater than maxValue.</exception> 
     public static int Next(int min, int max) 
     { 
      lock (myLock) 
      { 
       return random.Next(min, max); 
      } 
     } 

     /// <summary> 
     /// Returns a random number between 0.0 and 1.0. 
     /// </summary> 
     /// <returns>A double-precision floating point number greater than or equal to 0.0, and less than 1.0.</returns> 
     public static double NextDouble() 
     { 
      lock (myLock) 
      { 
       return random.NextDouble(); 
      } 
     } 

     /// <summary> 
     /// Fills the elements of a specified array of bytes with random numbers. 
     /// </summary> 
     /// <param name="buffer">An array of bytes to contain random numbers.</param> 
     /// <exception cref="ArgumentNullException">buffer is a null reference (Nothing in Visual Basic).</exception> 
     public static void NextBytes(byte[] buffer) 
     { 
      lock (myLock) 
      { 
       random.NextBytes(buffer); 
      } 
     } 
    } 
} 
+0

je pense que votre sur quelque chose !! la page cite "Si vous utilisez deux fois la même valeur de départ, vous obtiendrez la même séquence de nombres aléatoires.Al Random utilise l'heure actuelle comme la graine.Le code ci-dessus crée plusieurs instances dans une succession très rapide, et" l'heure actuelle " a tendance à avoir une granularité d'au moins 10ms, donc beaucoup d'instances partageront la même graine et créeront ainsi la même séquence de nombres. " Je crois que le code s'exécute aussi vite qu'il obtient le même code temporel "seed" que les autres panneaux et donc la même image. J'ai besoin d'une méthode aléatoire plus robuste. –

+0

@Ian - Jetez un oeil à la classe MiscUtility de Jon qui a un générateur aléatoire «Robuste». (lien en post). J'ai également édité le post pour inclure son code. –

+0

@ smurf Smurf, en utilisant le code de miscutility a résolu le problème. Merci à tous pour votre aide. –

0

Etes-vous sûr que votre page est pas mis en cache? Faire une source de vue sur la page. Oh et il devrait y avoir une fonction comme urand ou srand pour rendre aléatoire plus aléatoire.

+0

voir la source montre les 4 panneaux ayant la même URL BackgroundImage. rafraîchir la page remplace parfois toutes les 4 images avec un autre ensemble de 4, ou parfois il conserve la même chose. –

0

Je me demande si vous avez un certain niveau de mise en cache fonctionnant sur le panneau, ce qui l'empêche de passer par le traitement côté serveur en mode production.

+0

le code côté serveur doit fonctionner comme les images changent, bien que sur le site de production il change toutes les 4 images de panneau. L'exécution en mode débogage garantit que chaque panneau obtient sa propre image aléatoire .... –

+0

Exactement: il semble presque que le panneau exécute le traitement côté serveur sur la première instance, puis utilise une version en cache du contrôle pour les itérations 2 - 4. Je me demande si cela est dû à certaines optimisations de mode de production. Metro Smurf avait une bonne question sur la génération aléatoire - avez-vous été en mesure d'éliminer ce problème? Si oui, je voudrais regarder plus loin dans toute mise en cache .net qui pourrait se passer au niveau de la page ou de l'application –

+0

toujours en regardant dans le code numérique aléatoire –