IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez .NET Discussion :

Menu dynamique dans la zone de notification


Sujet :

Contribuez .NET

  1. #1
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2009
    Messages
    100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2009
    Messages : 100
    Points : 123
    Points
    123
    Par défaut Menu dynamique dans la zone de notification
    Bonjour à tous,

    Voir deuxième poste

    Je viens vous présenter ici ma modeste contribution. Mon projet est relativement simple :
    pouvoir creer facilement un menu dans la zone de notification.

    Pour ce faire, j'ai écrit la classe suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
     
    using System;
    using System.Drawing;
    using System.IO;
    using System.Reflection;
    using System.Windows.Forms;
    using System.Xml;
     
    namespace NotificationMenu {
    	public class SystemTrayMenu {
    		// Fields
    		private NotifyIcon _notifyIcon;
    		private MenuStrip _strip;
    		private ToolStripItemCollection _menus;
     
    		public SystemTrayIcon () {
    			this._notifyIcon = new NotifyIcon();
    			this._strip = new MenuStrip();
    			this._menus = new ToolStripItemCollection( _strip, new ToolStripItem[0] );
    		}
     
    		// Properties
    		public Icon Icon {
    			set { this._notifyIcon.Icon = value; }
    		}
     
    		public bool Visible {
    			set { this._notifyIcon.Visible = value; }
    		}
     
    		public ToolStripItemCollection Menu {
    			get { return this._menus; }
    		}
     
    		public ToolStripMenuItem this[string path] {
    			get {
    				string[] patterns = path.Split( '/' );
    				ToolStripMenuItem menu = (ToolStripMenuItem)_menus[patterns[1]];
     
    				for ( int i = 2 ; i < patterns.Length ; i++ )
    					if ( patterns[i] != "" )
    						try {
    							menu = (ToolStripMenuItem)menu.DropDownItems[patterns[i]];
    						} catch ( Exception ) {
    							throw new Exception( "The menu '" + patterns[i] + "' doesn't exist" );
    						}
     
    				return menu;
    			}
    		}
     
    		// Methods - public
    		public void LoadMenuFromXml ( string path ) {
    			XmlDocument xml = new XmlDocument();
     
    			using ( FileStream stream = new FileStream( path, FileMode.Open, FileAccess.Read ) ) {
    				xml.Load( stream );
    			}
     
    			LoadMenuFromXml( xml );
    		}
     
    		public void LoadMenuFromXml ( XmlDocument xml ) {
    			ToolStripMenuItem root = new ToolStripMenuItem();
     
    			foreach ( XmlNode node in xml.LastChild.ChildNodes )
    				Node2ToolStripMenu( node, ref root );
     
    			this._menus.AddRange( root.DropDownItems );
    			this._strip.Items.AddRange( _menus );
    			this._notifyIcon.ContextMenuStrip = this.BuildContextMenu();
    		}
     
    		public void ReloadContextMenu () {
    			this._notifyIcon.ContextMenuStrip = this.BuildContextMenu();
    		}
     
    		// Methods - private
    		private ContextMenuStrip BuildContextMenu () {
    			ContextMenuStrip retour = new ContextMenuStrip();
    			retour.Items.AddRange( this._menus );
    			return retour;
    		}
     
    		private void Node2ToolStripMenu ( XmlNode node, ref ToolStripMenuItem parent ) {
    			switch ( node.Name ) {
    				case "menu":
    					if ( node.HasChildNodes )
    						if ( node.Attributes["text"] != null ) {
    							ToolStripMenuItem actualMenu = NewMenuItem(
    								node.Attributes["name"] != null ?
    									node.Attributes["name"].Value :
    									null,
    								node.Attributes["text"].Value,
    								node.Attributes["icon"] != null ?
    									new Icon( node.Attributes["icon"].Value ).ToBitmap() :
    									null
    							);
     
    							parent.DropDownItems.Add( actualMenu );
     
    							foreach ( XmlNode child in node.ChildNodes )
    								Node2ToolStripMenu( child, ref actualMenu );
    						} else
    							throw new Exception( "The attribute 'text' can't be missing" );
    					else
    						if ( node.Attributes["text"] != null )
    							if ( node.Attributes["assembly"] != null && node.Attributes["type"] != null && node.Attributes["method"] != null )
    								parent.DropDownItems.Add(
    									AddEventHandler(
    										NewMenuItem(
    											node.Attributes["name"] != null ?
    												node.Attributes["name"].Value :
    												null,
    											node.Attributes["text"].Value,
    											node.Attributes["icon"] != null ?
    												new Icon( node.Attributes["icon"].Value ).ToBitmap() :
    												null
    										),
    										"Click",
    										node.Attributes["assembly"].Value,
    										node.Attributes["type"].Value,
    										node.Attributes["method"].Value
    									)
    								);
    							else
    								parent.DropDownItems.Add(
    									NewMenuItem(
    										node.Attributes["name"] != null ?
    											node.Attributes["name"].Value :
    											null,
    										node.Attributes["text"].Value,
    										node.Attributes["icon"] != null ?
    											new Icon( node.Attributes["icon"].Value ).ToBitmap() :
    											null
    									)
    								);
    						else
    							throw new Exception( "The attribute 'text' can't be missing" );
     
    					break;
    				case "separator":
    					parent.DropDownItems.Add( new ToolStripSeparator() );
    					break;
    				default:
    					throw new Exception( "Incorrect tag. It must be : menu or separator." );
    			}
     
    		}
     
    		private ToolStripMenuItem AddEventHandler ( ToolStripMenuItem menu, string eventType, string assembly, string type, string method ) {
    			menu.GetType().GetEvent( eventType ).AddEventHandler(
    				menu,
    				Delegate.CreateDelegate(
    					typeof( EventHandler ),
    					Assembly.Load( assembly ).GetType( type ).GetMethod( method )
    				)
    			);
     
    			return menu;
    		}
     
    		private ToolStripMenuItem NewMenuItem ( string text ) {
    			return new ToolStripMenuItem( text );
    		}
     
    		private ToolStripMenuItem NewMenuItem ( string text, Image icon ) {
    			return new ToolStripMenuItem( text, icon );
    		}
     
    		private ToolStripMenuItem NewMenuItem ( string text, ToolStripItem[] children ) {
    			return new ToolStripMenuItem( text, null, children );
    		}
     
    		private ToolStripMenuItem NewMenuItem ( string text, Image icon, ToolStripItem[] children ) {
    			return new ToolStripMenuItem( text, icon, children );
    		}
     
    		private ToolStripMenuItem NewMenuItem ( string name, string text ) {
    			return new ToolStripMenuItem( text, null, null, name );
    		}
     
    		private ToolStripMenuItem NewMenuItem ( string name, string text, Image icon ) {
    			return new ToolStripMenuItem( text, icon, null, name );
    		}
     
    		private ToolStripMenuItem NewMenuItem ( string name, string text, ToolStripItem[] children ) {
    			ToolStripMenuItem menu = new ToolStripMenuItem( text, null, children );
    			menu.Name = name;
     
    			return menu;
    		}
     
    		private ToolStripMenuItem NewMenuItem ( string name, string text, Image icon, ToolStripItem[] children ) {
    			ToolStripMenuItem menu = new ToolStripMenuItem( text, icon, children );
    			menu.Name = name;
     
    			return menu;
    		}
    	}
    }
    Pour ajouter des menus, il y a deux facons de le faire :
    • Par Xml :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
       
      <?xml version="1.0" encoding="utf-8"?>
      <root>
        <menu text="text" >
          <menu text="text" />
          <menu text="text" icon="icon.ico" />
        </menu>
        <menu text="text" >
          <menu text="text" assembly="assembly" type="namespace+classe" method="method" />
          <menu text="text" icon="icon.ico" />
        </menu>
        <separator/>
        <menu text="text" >
          <menu text="text" />
          <menu text="text" >
            <menu text="text" icon="icon.ico" assembly="assembly" type="namespace+classe" method="method"/ >
            <separator/>
            <menu text="text" assembly="assembly" type="namespace+classe" method="method" />
          </menu>
        </menu>
      </root>
      Les méthodes appelés dans le fichier XML doivent avoir le prototype suivant :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
       public static void Method (object sender, EventArgs e);
    • Ou directement dans le code :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
       
      SystemTrayIcon trayIcon = new SystemTrayIcon ();
      trayIcon.Menu.AddRange( new ToolStripItem[] {
      	new ToolStripMenuItem("menu1", new System.Drawing.Icon("icon.ico").ToBitmap(), new ToolStripItem[] {
      		new ToolStripMenuItem("menu11")
      	}),
      	new ToolStripMenuItem("menu2", null, new EventHandler(OnClick)),
      	new ToolStripMenuItem("menu3", new System.Drawing.Icon("icon.ico").ToBitmap())
      } );
       
      // A ne pas oublier pour prendre en compte les changements
      trayIcon.ReloadContextMenu();
       
      ToolStripMenuItem menu = trayIcon["/menu1/menu11"];


    A rajouter :
    • Des propositions ?


    Rajouter :
    • Possibilité de mettre des separateur avec la balise <separator/>
    • Passage de la classe de static à non static
    • Possibilité de modifier facilement les menu déjà creer par leur chemin ( ex: "/menu1/menu12" )


    J'espere que ca vous sera utile.
    Inarius

  2. #2
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2009
    Messages
    100
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2009
    Messages : 100
    Points : 123
    Points
    123
    Par défaut
    Apres un certain temps à ne plus y toucher, j'ai quelque peu repensé à cette classe, et en fait il y a un trou de sécurité béant

    Explication: on peut lancer n'importe quelle code dans n'importe quel assembly à partir des droits du programme. Donc il 'suffit' de changer les noms des assemblies, des types et des methodes pour obtenir le comportement que l'on veut et ainsi lancer n'importe quel code à partir des droits avec lesquels le programme a été lancé.

    J'ai donc apporter quelques modifications pour sécuriser (enfin je pense), j'ai aussi simplifier le code pour qu'il soit plus lisible. J'ai aussi rajouter la possibilite de ne plus seulement appelé des methodes 'public' et 'static' mais aussi des methodes de fonction instancié. J'ai aussi rajouté la possibilité de rendre le menu 'enabled' directement dans le XML.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
     
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.IO;
    using System.Windows.Forms;
    using System.Xml;
     
    namespace Library {
    	public class SystemTrayMenu {
    		private NotifyIcon _notifyIcon;
    		private MenuStrip _strip;
    		private ToolStripItemCollection _menus;
    		private Dictionary<string, EventHandler> _methods;
     
    		public SystemTrayMenu() {
    			this.Init( false, null );
    		}
     
    		public SystemTrayMenu( bool visible ) {
    			this.Init( visible, null );
    		}
     
    		public SystemTrayMenu( Icon icon ) {
    			this.Init( false, icon );
    		}
     
    		public SystemTrayMenu( bool visible, Icon icon ) {
    			this.Init( visible, icon );
    		}
     
    		public Icon Icon {
    			set { this._notifyIcon.Icon = value; }
    		}
     
    		public bool Visible {
    			set { this._notifyIcon.Visible = value; }
    		}
     
    		public ToolStripItemCollection Menus {
    			get { return this._menus; }
    		}
     
    		public Dictionary<string, EventHandler> Methods {
    			set { this._methods = value; }
    			get { return this._methods; }
    		}
     
    		public ToolStripMenuItem this[string path] {
    			get {
    				string[] nodes = path.Split( '/' );
    				ToolStripMenuItem menu = ( ToolStripMenuItem )_menus[nodes[1]];
     
    				for ( int i = 2 ; i < nodes.Length ; i++ )
    					if ( !String.IsNullOrEmpty( nodes[i] ) )
    						if ( ( menu = ( ToolStripMenuItem )menu.DropDownItems[nodes[i]] ) == null )
    							throw new Exception( "The menu '" + nodes[i] + "' doesn't exist or his attributes 'name' is not defined" );
    						else
    							throw new Exception( "A menu can't have an empty or null attribute 'name'" );
     
    				return menu;
    			}
    		}
     
    		public void LoadMenuFromXml( string path ) {
    			XmlDocument xml = new XmlDocument();
     
    			using ( FileStream stream = new FileStream( path, FileMode.Open, FileAccess.Read ) )
    				xml.Load( stream );
     
    			LoadMenuFromXml( xml );
    		}
     
    		public void LoadMenuFromXml( XmlDocument xml ) {
    			ToolStripMenuItem root = new ToolStripMenuItem();
     
    			foreach ( XmlNode node in xml.LastChild.ChildNodes )
    				BuildToolStripMenu( node, ref root );
     
    			this._menus.AddRange( root.DropDownItems );
    			this._strip.Items.AddRange( _menus );
    			this._notifyIcon.ContextMenuStrip = this.BuildContextMenu();
    		}
     
    		public void ReloadContextMenu() {
    			this._notifyIcon.ContextMenuStrip = this.BuildContextMenu();
    		}
     
    		private ContextMenuStrip BuildContextMenu() {
    			ContextMenuStrip retour = new ContextMenuStrip();
    			retour.Items.AddRange( this._menus );
    			return retour;
    		}
     
    		private void BuildToolStripMenu( XmlNode node, ref ToolStripMenuItem parent ) {
    			switch ( node.Name ) {
    				case "menu":
    					if ( node.Attributes["text"] != null ) {
    						ToolStripMenuItem menu = new ToolStripMenuItem(
    							node.Attributes["text"].Value,
    							node.Attributes["icon"] != null ? new Icon( node.Attributes["icon"].Value ).ToBitmap() : null,
    							node.Attributes["method_key"] != null ? this._methods[node.Attributes["method_key"].Value] : null,
    							node.Attributes["name"] != null ? node.Attributes["name"].Value : null
    						);
     
    						menu.Enabled = node.Attributes["enabled"] != null ? bool.Parse( node.Attributes["enabled"].Value ) : true;
     
    						parent.DropDownItems.Add( menu );
     
    						if ( node.HasChildNodes )
    							foreach ( XmlNode child in node.ChildNodes )
    								this.BuildToolStripMenu( child, ref menu );
    					} else
    						throw new Exception( "The attribute 'text' can't be missing" );
     
    					break;
    				case "separator":
    					parent.DropDownItems.Add( new ToolStripSeparator() );
    					break;
    				default:
    					throw new Exception( "Incorrect tag. It must be : menu or separator." );
    			}
     
    		}
     
    		private void Init( bool visible, Icon icon ) {
    			this._strip = new MenuStrip();
    			this._menus = new ToolStripItemCollection( _strip, new ToolStripItem[0] );
    			this._methods = new Dictionary<string, EventHandler>();
    			this._notifyIcon = new NotifyIcon();
    			this._notifyIcon.Visible = visible;
     
    			if ( icon != null )
    				this._notifyIcon.Icon = icon;
    		}
    	}
    }
    Desormais pour utiliser ce menu, il faudra faire de cette manière:
    1. Dans le code : Il faut toujours instancié le menu, mais il faut aussi remplir le tableau qui fait la correspondance entre le nom des méthodes dans le XML, et les methodes du programme. Cela permet de sécuriser car il n'est plus possible d'appeler n'importe quel méthode non définie dans le programme, mais aussi de pourvoir appeler des methodes de classe instancié.

      Pour initialiser le menu
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
       
      Test test = new Test();
       
      _trayMenu = new SystemTrayMenu( true, new Icon( "icon.ico" ) );
      _trayMenu.Methods.Add( "Hello", new System.EventHandler( HelloWorld ) );
      _trayMenu.Methods.Add( "Test", new System.EventHandler( test.Function ) );
      _trayMenu.LoadMenuFromXml( "menu_zone_notification.xml" );
      Les différentes méthodes appelés
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
       
      private static void HelloWorld( object sender, EventArgs e ) {
      	MessageBox.Show( "World" ); 
      }
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
       
      public class Test {
      	public void Function( object sender, EventArgs e ) {
      		MessageBox.Show( "In Test" );
      	}
      }
    2. Dans le XML : ne change presque pas
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
       
      <?xml version="1.0" encoding="UTF-8"?>
      <root>
      	<menu text="Menu 1" name="1">
      		<menu text="Menu 11" name="1" method_key="Test" />
      		<separator />
      		<menu text="Menu 12" name="2" method_key="Hello" />
      	</menu>
      	<separator />
      	<menu text="Menu 2" name="2">
      		<menu text="Menu 21" name="1" method_key="Hello" />
      	</menu>
      </root>
      Les différents attributs reconnus sont:
      • text ( obligatoire )
      • name: utile lorsque l'on veut "parcourir" l'arbre des menus pour changer un icone, ou le texte, ...
      • icon: icone du menu
      • method_key: la clé correspondante à la méthode devant être appelé lors du Click sur le menu
      • enabled : ( valeur : true ou false )

Discussions similaires

  1. Icone dans la zone de notification
    Par LesLemmings dans le forum Visual C++
    Réponses: 16
    Dernier message: 17/04/2007, 16h10
  2. Réponses: 4
    Dernier message: 11/07/2006, 11h19
  3. Menu dynamique dans calque
    Par Invité dans le forum Balisage (X)HTML et validation W3C
    Réponses: 7
    Dernier message: 07/06/2006, 10h37
  4. Créer un menu contextuel dans une zone de liste
    Par 973thom dans le forum Access
    Réponses: 10
    Dernier message: 13/09/2005, 23h59
  5. [CODE] Application dans la zone de notification
    Par Rodrigue dans le forum C++Builder
    Réponses: 4
    Dernier message: 29/05/2003, 19h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo