Overblog
Suivre ce blog Administration + Créer mon blog
5 mai 2010 3 05 /05 /mai /2010 15:35

 

Si vous aviez l’habitude d’utiliser My.Computer.Keyboard.SendKeys avec Winform, vous avez pu constater que cela ne fonctionne pas aussi bien sous WPF.

 

Voici ce que l’on aurait fait avec Winform pour simuler l’appuie de la flèche du bas :

Code :

My.Computer.Keyboard.SendKeys("{DOWN}")

 

 

Le code suivant simule l’appuie sur la flèche du bas en WPF :

Code :

Dim kea As New KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Down)
kea.RoutedEvent = Keyboard.KeyDownEvent

InputManager.Current.ProcessInput(kea)

 

On obtient le même résultat avec le code suivant :

 

Code :

Dim target As System.Windows.IInputElement = Keyboard.FocusedElement
Dim kea As New KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Down)
kea.RoutedEvent = Keyboard.KeyDownEvent
target.RaiseEvent(kea)

 

Le second code est intéressant si vous voulez simuler l’appuie d'une touche sur un control qui n’a pas forcément le focus. Il suffit alors de modifier la variable “target”.

Partager cet article
Repost0
28 avril 2010 3 28 /04 /avril /2010 07:47

Mon objectif est le suivant : Sauvegarder dans un même fichier XML les données d’un Dataset et les préférences de l’utilisateur pour faire une sauvegarde globale de mon application.

Un dataset est par nature “Serializable” mais il n’en est pas de même pour l’objet My.Settings dont le niveau de protection est trop élevé pour être sérialisé.

J’ai donc décidé de faire une classe personnalisée “Serializable” pour stocker les préférences de l’utilisateur et une extension “My.Preferences”

 

Pour sérialiser et désérialiser des objets j’ai créé une classe dans l’espace de nom HC.Xml dont voici le code :

Code:

Imports System.Xml
Imports System.IO
Imports System.Xml.Serialization

Public Class Serialization

    Private _obj As Object

    Public Sub New(ByVal obj As Object)
        _obj = obj
    End Sub

    Public Sub WriteToXmlFile(ByVal filePath As String)
        Dim stream As StreamWriter = New StreamWriter(filePath)
        Dim serializer As XmlSerializer = New XmlSerializer(_obj.GetType)
        serializer.Serialize(stream, _obj)
        stream.Close()
    End Sub

    Public Function ConvertXmlFileToObject(ByVal filePath As String)
        Dim stream As StreamReader = New StreamReader(filePath)
        Dim serializer As XmlSerializer = New XmlSerializer(_obj.GetType)
        _obj = serializer.Deserialize(stream)
        stream.Close()
        Return _obj
    End Function

End Class

 

J’ai ensuite créé ma classe personnalisé “customSettings” qui est dans l’espace de nom Version1 de mon application :

 

Code :

Imports System.Xml
Imports System.Xml.Serialization

Namespace Version1
    <Serializable(), XmlRoot()> _
    Public Class customSettings

        Public Sub New()
            Me.Load()
        End Sub

        Public Sub Save()
            Dim xmlFile As New HC.Xml.Serialization(Me)
            xmlFile.WriteToXmlFile(My.Application.Info.DirectoryPath & "preferences.xml")
        End Sub

        Public Sub Load()
            Dim filePath As String = My.Application.Info.DirectoryPath & "preferences.xml"
            If My.Computer.FileSystem.FileExists(filePath) Then
                Dim xmlFile As New HC.Xml.Serialization(Me)
                xmlFile.ConvertXmlFileToObject(filePath)
            End If
        End Sub

        Private chargesSurVenteValue As Decimal = 13
        <XmlElement()> _
        Public Property ChargeSurVente() As Decimal
            Get
                Return chargesSurVenteValue
            End Get
            Set(ByVal value As Decimal)
                chargesSurVenteValue = value
            End Set
        End Property

        Private chargesSurServiceValue As Decimal = 23
        <XmlElement()> _
        Public Property ChargesSurService() As Decimal
            Get
                Return chargesSurServiceValue
            End Get
            Set(ByVal value As Decimal)
                chargesSurServiceValue = value
            End Set
        End Property

    End Class
End Namespace

 

 

Je dois maintenant ajouter cette classe à l’espace de nom My :

 

Code :

Namespace My
    <HideModuleName()> _
    Module customPreferences
        Private _pref As New ThreadSafeObjectProvider(Of customSettings)
        Public ReadOnly Property Preferences As customSettings
            Get
                Return _pref.GetInstance
            End Get
        End Property
    End Module
End Namespace

Remarquez que si “HideModuleName” n’était pas spécifié, nous aurions My.customPreferences.Preferences au lieu de My.Preferences. 

 

Voilà, je peux désormais utiliser My.Preferences pour stocker les préférences de mon utilisateur. Lorsque je utilise la méthode My.Preferences.Save, l’objet est sérialisé et sauvegarder dans le fichier xml “preferences.xml” dans le répertoire de mon application. La méthode Load permet de désérialiser l’objet pour récupérer les données et est appelé dans le constructeur.

 

Pour pouvoir faire ma sauvegarde globale, il ne me reste plus qu’a créer une classe “serializable” contenant mon dataset et mes préférences.

 

Code :

Public Class Backup

        Private ds As New DataSetAGPV1

        Public Sub BackupDatabaseAndSettings(Optional ByVal fileName As String = Nothing)
            Me.FillDataset()

            Dim bkf As New BackupFile
            bkf.DataSet = ds
            bkf.Preferences = My.Preferences

            Dim XmlSerial As New HC.Xml.Serialization(bkf)

            If fileName IsNot Nothing Then
                XmlSerial.WriteToXmlFile(fileName)
             End If
        End Sub

        Private Sub FillDataset()
            For Each dt As DataTable In ds.Tables
                FillTable(dt)
            Next

        End Sub

        Private Sub FillTable(ByVal dt As DataTable)
            Using con As New SqlConnection(My.Settings.dbAGPV1ConnectionString)
                Using da As New SqlDataAdapter("SELECT * FROM " & dt.TableName, con)
                    da.Fill(ds, dt.TableName)
                End Using
            End Using
        End Sub

        <Serializable(), XmlRoot()> _
        Public Class BackupFile

            Private _version As String

            Public Sub New()
                _version = My.Application.Info.Version.ToString
            End Sub

            <XmlAttribute()> _
            Public Property Version As String
                Get
                    Return _version
                End Get
                Set(ByVal value As String)
                    _version = value
                End Set
            End Property

            Private ds As DataSetAGPV1
            <XmlElement()> _
            Public Property DataSet() As DataSetAGPV1
                Get
                    Return ds
                End Get
                Set(ByVal value As DataSetAGPV1)
                    ds = value
                End Set
            End Property

            Private preferencesValue As Version1.customSettings
            <XmlElement()> _
            Public Property Preferences() As Version1.customSettings
                Get
                    Return preferencesValue
                End Get
                Set(ByVal value As Version1.customSettings)
                    preferencesValue = value
                End Set
            End Property

        End Class

    End Class

 

La classe Backup charge les données dans le dataset avant de le mettre dans la classe “serializable” BackupFile avec les préférences. Ensuite la classe Backup file est sérialisé et sauvegardée sous la forme d’un fichier XML. J’ai ainsi sauvegarder les données de mon application et les préférences de l’utilisateur dans un même fichier.

La classe BackupFile contient également une propriété “Version” qui permet, lors de la restauration de données, de vérifier si la version de l’application et de la sauvegarde sont les même.

Partager cet article
Repost0
9 avril 2010 5 09 /04 /avril /2010 18:33

Le développeurs ont pris l’habitude de manipuler les données à l’aide de Dataset et de DataTable. Depuis l’arrivé  de LINQ leurs habitudes ont un peu changé et ils ont du s’habituer à travailler plus souvent avec des IEnumerable(of Anonyme).

La méthode CopyToDatatable permet de copier les résultats d’une requête LINQ dans un DataTable.

 

Voici un exemple :

 

Code :

Dim dt As New DataTable

Dim resultat = From element As DataRow in maDataTable Where element.monChamp=maVariable Select element

resultat.CopyToDataTable(dt)

Cette méthode est très pratique si l’on veut continuer de travailler avec des DataTables. Le problème c’est que cette méthode n’est disponible que si le résultat de votre requête LINQ est de type DataRow.

 

Pour pouvoir utiliser CopyToDataTable pour d’autres types, vous devez ajouter le code suivant à votre application.

 

Créez une classe ObjectShredder(Of T) (ce code provient de MSDN) :

 

Code :

Imports System.Reflection

Public Class ObjectShredder(Of T)

    Private _fi As FieldInfo()
    Private _ordinalMap As Dictionary(Of String, Integer)
    Private _pi As PropertyInfo()
    Private _type As Type

  
    Public Sub New()
        Me._type = GetType(T)
        Me._fi = Me._type.GetFields
        Me._pi = Me._type.GetProperties
        Me._ordinalMap = New Dictionary(Of String, Integer)
    End Sub

    Public Function ShredObject(ByVal table As DataTable, ByVal instance As T) As Object()
        Dim fi As FieldInfo() = Me._fi
        Dim pi As PropertyInfo() = Me._pi
        If (Not instance.GetType Is GetType(T)) Then
            ' Si l'instance dérive de T, étendre le schéma de la table
            ' et récupérer les propirétés et les champs
            Me.ExtendTable(table, instance.GetType)
            fi = instance.GetType.GetFields
            pi = instance.GetType.GetProperties
        End If

        ' Add the property and field values of the instance to an array.
        Dim values As Object() = New Object(table.Columns.Count - 1) {}
        Dim f As FieldInfo
        For Each f In fi
            values(Me._ordinalMap.Item(f.Name)) = f.GetValue(instance)
        Next
        Dim p As PropertyInfo
        For Each p In pi
            values(Me._ordinalMap.Item(p.Name)) = p.GetValue(instance, Nothing)
        Next

        ' Return the property and field values of the instance.
        Return values
    End Function

    ' Summary:           Loads a DataTable from a sequence of objects.
    ' source parameter:  The sequence of objects to load into the DataTable.</param>
    ' table parameter:   The input table. The schema of the table must match that
    '                    the type T.  If the table is null, a new table is created 
    '                    with a schema created from the public properties and fields
    '                    of the type T.
    ' options parameter: Specifies how values from the source sequence will be applied to
    '                    existing rows in the table.
    ' Returns:           A DataTable created from the source sequence.

    Public Function Shred(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable

        ' Load the table from the scalar sequence if T is a primitive type.
        If GetType(T).IsPrimitive Then
            Return Me.ShredPrimitive(source, table, options)
        End If

        ' Create a new table if the input table is null.
        If (table Is Nothing) Then
            table = New DataTable(GetType(T).Name)
        End If

        ' Initialize the ordinal map and extend the table schema based on type T.
        table = Me.ExtendTable(table, GetType(T))

        ' Enumerate the source sequence and load the object values into rows.
        table.BeginLoadData()
        Using e As IEnumerator(Of T) = source.GetEnumerator
            Do While e.MoveNext
                If options.HasValue Then
                    table.LoadDataRow(Me.ShredObject(table, e.Current), options.Value)
                Else
                    table.LoadDataRow(Me.ShredObject(table, e.Current), True)
                End If
            Loop
        End Using
        table.EndLoadData()

        ' Return the table.
        Return table
    End Function

    Public Function ShredPrimitive(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable
        ' Create a new table if the input table is null.
        If (table Is Nothing) Then
            table = New DataTable(GetType(T).Name)
        End If
        If Not table.Columns.Contains("Value") Then
            table.Columns.Add("Value", GetType(T))
        End If

        ' Enumerate the source sequence and load the scalar values into rows.
        table.BeginLoadData()
        Using e As IEnumerator(Of T) = source.GetEnumerator
            Dim values As Object() = New Object(table.Columns.Count - 1) {}
            Do While e.MoveNext
                values(table.Columns.Item("Value").Ordinal) = e.Current
                If options.HasValue Then
                    table.LoadDataRow(values, options.Value)
                Else
                    table.LoadDataRow(values, True)
                End If
            Loop
        End Using
        table.EndLoadData()

        ' Return the table.
        Return table
    End Function

    Public Function ExtendTable(ByVal table As DataTable, ByVal type As Type) As DataTable
        ' Extend the table schema if the input table was null or if the value
        ' in the sequence is derived from type T.
        Dim f As FieldInfo
        Dim p As PropertyInfo

        For Each f In type.GetFields
            If Not Me._ordinalMap.ContainsKey(f.Name) Then
                Dim dc As DataColumn

                ' Add the field as a column in the table if it doesn't exist
                ' already.
                dc = IIf(table.Columns.Contains(f.Name), table.Columns.Item(f.Name), table.Columns.Add(f.Name, f.FieldType))

                ' Add the field to the ordinal map.
                Me._ordinalMap.Add(f.Name, dc.Ordinal)
            End If

        Next

        For Each p In type.GetProperties
            If Not Me._ordinalMap.ContainsKey(p.Name) Then
                ' Add the property as a column in the table if it doesn't exist
                ' already.
                Dim dc As DataColumn
                dc = IIf(table.Columns.Contains(p.Name), table.Columns.Item(p.Name), table.Columns.Add(p.Name, p.PropertyType))

                ' Add the property to the ordinal map.
                Me._ordinalMap.Add(p.Name, dc.Ordinal)
            End If
        Next

        ' Return the table.
        Return table
    End Function

End Class

 

 

Ensuite, créez un module :

 

Code :

Imports System.Runtime.CompilerServices

Public Module CustomLINQtoDataSetMethods
    <Extension()> _
    Public Function CopyToDataTable(Of T)(ByVal source As IEnumerable(Of T)) As DataTable
        Return New ObjectShredder(Of T)().Shred(source, Nothing, Nothing)
    End Function

    <Extension()> _
    Public Function CopyToDataTable(Of T)(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable
        Return New ObjectShredder(Of T)().Shred(source, table, options)
    End Function

End Module

 

Vous pouvez désormais utiliser CopyToDataTable avec d’autres Types !

Partager cet article
Repost0
8 avril 2010 4 08 /04 /avril /2010 17:47

En Winform, lorsqu’une fenêtre en appelle une autre, celle-ci devient automatiquement son parent et il est facile de l’obtenir avec un simple Me.parent.

En WPF ceci n’est pas automatique. Me.Parent retournera au pire “Nothing”. Avant d’appeler votre fenêtre enfant vous devez préciser qui est son Owner.

 

Code :

Dim win As New maWindowEnfant


'défini la fenêtre active comme la fenêtre parent
Dim parent As maWindowParent = Window.GetWindow(Me)
win.Owner = parent


If win.ShowDialog() = True Then

        ‘ mon code

End If

 

 

Dans la fenêtre enfant vous pouvez maintenant retrouver la fenêtre parent de la façon suivante :

 

Code :

Dim parent As maWindowParent = Me.Owner

Partager cet article
Repost0
20 mars 2010 6 20 /03 /mars /2010 10:47

Si certain d’entre vous n’arrives plus à envoyer d’email via le serveur stmp.sfr.fr, inutile d’appeler leur hotline, ils ne vous donnerons pas la solution.

 

Voici la solution.

Dans votre logiciel d’email :

Changer le serveur smtp en : smtp-auth.sfr.fr

Changez le port du smtp (25 par défaut) en : 587

Indiquez que votre serveur de courrier sortant (smtp) requiert une authentification et identifiez vous à l’aide de votre adresse email (cegetel, neuf ou sfr) et votre mot de passe.

 

Ainsi vos courrier retrouverons le chemin de la liberté :)

Partager cet article
Repost0
10 mars 2010 3 10 /03 /mars /2010 09:26

Il est parfois nécessaire d’empêcher la saisie d’une adresse e-mail ou d’un site internet dans un texte pour des raisons de sécurité, ou tout simplement pour que l’utilisateur ne saisissent ses informations qu’aux endroits prévus à cet effet.

 

Voici 2 fonctions qui permettent de savoir si une adresse email ou un site internet a été saisie dans un texte :

 

Code :

Private Function IsWebSiteInText(ByVal txt As String) As Boolean
        Dim regx As New Regex("http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", RegexOptions.IgnoreCase)

        Dim mactches As MatchCollection = regx.Matches(txt)

        If mactches.Count > 0 Then
            Return True
        End If

        Return False

End Function

 

Private Function IsEmailInText(ByVal txt As String) As Boolean

        Dim regx As New Regex("\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",RegexOptions.IgnoreCase)

        Dim mactches As MatchCollection = regx.Matches(txt)

        If mactches.Count > 0 Then
            Return True
        End If

        Return False
End Function

Dans le cas d’un formulaire ASP.NET vous pouvez utiliser un CustomValidator pour vérifier le texte.

Partager cet article
Repost0
27 janvier 2010 3 27 /01 /janvier /2010 10:28

Le format Torrent est une bonne alternative au P2P. Il est souvent plus rapide. Néanmoins, pour une même recherche, vous obtiendrez souvent moins de résultats avec les Torrents qu’avec le P2P.

 

Il est nécessaire de passer par un moteur de recherche de Torrents pour trouver les fichiers que l’on veut télécharger.

En voici quelques un parmi les meilleurs :

http://www.torrentz.com/

http://www.demonoid.com/

http://isohunt.com/

http://btjunkie.org/

 

Il existe plusieurs logiciels permettant de télécharger des Torrents. Voici ceux que je vous recommande :

http://www.bittorrent.com/

http://www.utorrent.com/

 

Il n’est pas illégal d’utiliser ces logiciels. Ce qui est illégal c’est de télécharger des fichiers protégés par des copyright à l’aide de ces logiciels. Beaucoup d’entreprise aujourd’hui utilisent les torrents pour accélérer le téléchargement de leurs offres légales (musiques, jeux, logiciels etc. ).

Partager cet article
Repost0
27 novembre 2009 5 27 /11 /novembre /2009 09:24
GigaNews lance leur service VPN baptisé VyprVPN. La version Beta est accessible gratuitement aux abonnés Diamond et sur invitation jusqu'en Juin 2010. Ils proposent 2 serveurs VPN : L'un est aux USA et l'autre en Europe.
Leurs serveurs laissent passer les connexion NNTP, P2P et Torrent.
Je l'ai testé sous Windows Vista et cela fonctionne très bien et pratiquement sans perte de bande passante. Très facile à installer ce réseau VPN est le meilleur service VPN que j'ai trouvé à ce jour.
Idéal pour contourner des restrictions ou des filtrages de votre fournisseur d'accès à Internet.
Partager cet article
Repost0
16 novembre 2009 1 16 /11 /novembre /2009 15:07

Vous trouverez beaucoup d’exemples de TextBox Numérique pour WPF sur internet. Malheureusement aucun ne prends en compte le remplacement du point par la virgule et n’empêche l’utilisateur de saisir plusieurs virgules. Voici donc un control utilisateur qui prend en compte ces particularités françaises.

 

Code :

Partial Public Class TextBoxNumeric
    Inherits TextBox

    Protected Overloads Overrides Sub OnPreviewTextInput(ByVal e As System.Windows.Input.TextCompositionEventArgs)

        Dim tb As TextBoxNumeric = CType(e.Source, TextBoxNumeric)

        If tb.Text.Contains(".") Or tb.Text.Contains(",") And (e.Text = "." Or e.Text = ",") Then
            e.Handled = True
            Exit Sub
        Else
            If System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator <> "." And e.Text = "." Then
                tb.Text = tb.Text & System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator
                tb.SelectionStart = tb.Text.Length
                e.Handled = True
                Exit Sub
            End If
        End If

        e.Handled = Not AreAllValidNumericChars(e.Text)

        MyBase.OnPreviewTextInput(e)
    End Sub

    Private Function AreAllValidNumericChars(ByVal str As String) As Boolean
        Dim ret As Boolean = True

        If str = System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyGroupSeparator Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.CurrencySymbol Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.NegativeSign Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.NegativeInfinitySymbol Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.NumberGroupSeparator Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.PercentDecimalSeparator Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.PercentGroupSeparator Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.PercentSymbol Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.PerMilleSymbol Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.PositiveInfinitySymbol Or _
            str = System.Globalization.NumberFormatInfo.CurrentInfo.PositiveSign Then
            Return ret
        End If

        Dim l As Integer = str.Length
        For i As Integer = 0 To l - 1
            Dim ch As Char = str(i)
            ret = ret And [Char].IsDigit(ch)
        Next

        Return ret
    End Function

End Class

Partager cet article
Repost0
10 novembre 2009 2 10 /11 /novembre /2009 15:20

Dans un article précédent (voir ici) j’expliquais comment obtenir le comportement d’un RadioButton avec un CheckBox dans un DataGridView en Winform sans créer de contrôle utilisateur personnalisé.

Nous allons voir dans cet article comment obtenir le même résultat en WPF en utilisant uniquement le code XAML.

 

Code XAML :

<my1:DataGrid AutoGenerateColumns="False" Margin="6,82,6,6" Name="DataGridRadioButtonDemo" xmlns:my1="http://schemas.microsoft.com/wpf/2008/toolkit" SelectionMode="Single" SelectionUnit="Cell">
                        <my1:DataGrid.Columns>
                            <my1:DataGridTemplateColumn Header="Selection"  >
                                <my1:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <RadioButton GroupName="GroupBoxSelection" IsChecked="{Binding Path=maSelection}" HorizontalAlignment="Center"   ></RadioButton>
                                    </DataTemplate>
                                </my1:DataGridTemplateColumn.CellTemplate>
                                <my1:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <RadioButton GroupName="GroupBoxSelection" IsChecked="{Binding Path=maSelection}" HorizontalAlignment="Center"  ></RadioButton>
                                    </DataTemplate>
                                </my1:DataGridTemplateColumn.CellEditingTemplate>
                            </my1:DataGridTemplateColumn>
                         </my1:DataGrid.Columns>
                    </my1:DataGrid>

 

 

Les RadioButton sont ici lié avec une table ayant un champ “maSelection”. Le faite de mettre tous les RadioButton du DataGrid dans le GroupName “GroupBoxSelection” permet d’obtenir l’effet désiré.

 

ATTENTION :  A cause d’un bug connu de Microsoft depuis la version 3 du framework, les données ne se mettent pas à jour lors du changement Checked/Unchecked des RadioButton. Ce bug semble avoir été corrigé dans la version 4 du framework à venir avec la version 2010 de Visual Studio. J’espère pouvoir fournir bientôt un article expliquant comment contourner ce problème avec la version 3.5 du framework.

Partager cet article
Repost0