none
Save location of several labels. RRS feed

  • Question

  • Hello,

    I want to save the location of a lot of labels. Instead of listing each one individually in My.Settings, is there a better way to do it? Something similar to using System.Collections.Specialized.StringCollection for saving text in several textboxes.

    Thank you.

    Thursday, August 20, 2015 2:48 PM

Answers

  • As Reed has already said there a lot of possible solutions here.

    For instance you could use a DataBase but that may be a little heavy for your application.

    You could also create an XML file that could be used. Something like:

    <Year>
        <Number>2015</Number>
        <Months>
             <Month>
                  <Name>August</Name>
                  <Days>
                       <Day>
                            <Number>1<\Number>
                            <Labels>
                                 <Label>
                                      <Text>Some Label Text</Text>
                                 </Label>
                            </Labels>
                       </Day>
                   </Days>
              </Month>
         </Months>
    </Year>



    Programming is easy, understanding how is not.

    • Marked as answer by grandpaagain Friday, August 21, 2015 8:48 AM
    Thursday, August 20, 2015 4:23 PM
  • How about a List Of(Int32)?

    Divide up the bits, use some for year, month, x and y.

    • Marked as answer by grandpaagain Friday, August 21, 2015 8:49 AM
    Thursday, August 20, 2015 7:48 PM
  • I have 25 labels that I can drag around and leave on certain spots on the calendar.

    Firstly, get your labels into a List(Of Label).   That means you can process them in a loop, simplifying the code.  It might also simplify other parts of the application.

    To use settings for your storage you can convert a sequence of numbers into a comma-delimited string.

    So the 'save' loop just loops through the list of labels and appends each pair of values from the Location property to the string, with their separating commas.

    The 'restore' loop firstly splits the string into an array of string (using Split), then loops through the list of labels, picking up array items two at a time, converting to Integer then Point, and setting the location value for the label.

    That would get you down to 48 settings variables.

    To reduce that further you can combine the above procedure to make one string from all labels to 12 months - that would be four strings, one for each year.

    Or, you can use a variation of the above procedure with one string for each label, and no predefined length for each string.  That is, the sequence of values starts with a nominated month and year and goes as far as you have defined label locations. It can grow as you define positions for more months.  That's 25 settings variables, which is definitely manageable.

    • Edited by Acamar Thursday, August 20, 2015 9:41 PM sp
    • Marked as answer by grandpaagain Friday, August 21, 2015 8:49 AM
    Thursday, August 20, 2015 9:35 PM
  • Thank you for the additional detail, it is very helpful.

    For something like this I would suggest creating your own data container class to hold the label positions, something like the following code.  In this example the labels are referred to by name, but you could also refer to them by an index number; I'm not sure what is most appropriate as it depends on how the form is actually laid out.

    Option Strict On
    
    Public Class Form1
        Private labelData As New CalendarLabelData
        Private dataPath As String = IO.Path.Combine(My.Application.Info.DirectoryPath, "labels.dat")
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            If IO.File.Exists(dataPath) Then labelData.Load(dataPath)
        End Sub
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            labelData.Save(dataPath)
        End Sub
    End Class
    
    Public Class CalendarLabelData
        Private listCore As New Dictionary(Of MonthYear, Dictionary(Of String, Point))
    
        Public Function GetLocation(year As Integer, month As Integer, labelName As String) As Point
            Dim target As New MonthYear(month, year)
            If Not listCore.ContainsKey(target) Then Return Point.Empty
            If Not listCore(target).ContainsKey(labelName) Then Return Point.Empty
            Return listCore(target)(labelName)
        End Function
    
        Public Sub Load(filePath As String)
            Using fs As IO.FileStream = IO.File.Open(filePath, IO.FileMode.Open)
                Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                listCore = CType(bf.Deserialize(fs), Dictionary(Of MonthYear, Dictionary(Of String, Point)))
            End Using
        End Sub
    
        Public Sub SetLocation(year As Integer, month As Integer, labelName As String, labelLocation As Point)
            Dim target As New MonthYear(month, year)
            If Not listCore.ContainsKey(target) Then listCore.Add(target, New Dictionary(Of String, Point))
            listCore(target)(labelName) = labelLocation
        End Sub
    
        Public Sub Save(filePath As String)
            Using fs As IO.FileStream = IO.File.Open(filePath, IO.FileMode.OpenOrCreate)
                Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                bf.Serialize(fs, listCore)
            End Using
        End Sub
    
        <Serializable()>
        Private Structure MonthYear
            Public Month As Integer
            Public Year As Integer
            Public Sub New(m As Integer, y As Integer)
                Month = m
                Year = y
            End Sub
        End Structure
    End Class

    With this example you can call labelData.GetLocation() and pass the year, month, and label name to get the stored position.  The example shows how you can persist the location data to a binary file stored alongside the executable.

    If the 25 labels in question are the only labels in that parent control then you might have a loop something like the following for setting all of the locations:

    Dim year, month As Integer
    'set year and month according to calendar selection
    For Each lbl As Label In Controls.OfType(Of Label)
        lbl.Location = labelData.GetLocation(year, month, lbl.Name)
    Next
    

    Exactly how you go about setting and retrieving the positions depends on the layout of the form (this loop won't work if there are other labels in the same parent besides the 25 in question).


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by grandpaagain Friday, August 21, 2015 8:49 AM
    Thursday, August 20, 2015 10:11 PM
    Moderator

All replies

  • There are a number of potential solutions here... but it would help to understand more about what you are working with.

    When you say you want to save the location of a lot of labels, are you referring to the Label.Location property value of multiple Label controls on your form?  If so, how do those controls change location at run-time?  Have you added code that allows a user to drag them around or otherwise specify their position in the form?  Or do you programmatically move these labels based on some criteria?


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Thursday, August 20, 2015 3:20 PM
    Moderator
  • I have a calendar I use to keep track of things that pertain to my job.  I have 25 labels that I can drag around and leave on certain spots on the calendar. So for the month of August the labels need to be in a certain location. When I advance the calendar to September, the labels need to be in a different location. As I move forwards and backwards through the months I need to labels to be where I placed them for each month. I can use My.Settings.Point for each label, but to do that for 25 labels, for 12 months, for 4 years, the list is incredibly long and time consuming.

    I hope that helps and is not too confusing.

    Thursday, August 20, 2015 3:29 PM
  • As Reed has already said there a lot of possible solutions here.

    For instance you could use a DataBase but that may be a little heavy for your application.

    You could also create an XML file that could be used. Something like:

    <Year>
        <Number>2015</Number>
        <Months>
             <Month>
                  <Name>August</Name>
                  <Days>
                       <Day>
                            <Number>1<\Number>
                            <Labels>
                                 <Label>
                                      <Text>Some Label Text</Text>
                                 </Label>
                            </Labels>
                       </Day>
                   </Days>
              </Month>
         </Months>
    </Year>



    Programming is easy, understanding how is not.

    • Marked as answer by grandpaagain Friday, August 21, 2015 8:48 AM
    Thursday, August 20, 2015 4:23 PM
  • How about a List Of(Int32)?

    Divide up the bits, use some for year, month, x and y.

    • Marked as answer by grandpaagain Friday, August 21, 2015 8:49 AM
    Thursday, August 20, 2015 7:48 PM
  • I have 25 labels that I can drag around and leave on certain spots on the calendar.

    Firstly, get your labels into a List(Of Label).   That means you can process them in a loop, simplifying the code.  It might also simplify other parts of the application.

    To use settings for your storage you can convert a sequence of numbers into a comma-delimited string.

    So the 'save' loop just loops through the list of labels and appends each pair of values from the Location property to the string, with their separating commas.

    The 'restore' loop firstly splits the string into an array of string (using Split), then loops through the list of labels, picking up array items two at a time, converting to Integer then Point, and setting the location value for the label.

    That would get you down to 48 settings variables.

    To reduce that further you can combine the above procedure to make one string from all labels to 12 months - that would be four strings, one for each year.

    Or, you can use a variation of the above procedure with one string for each label, and no predefined length for each string.  That is, the sequence of values starts with a nominated month and year and goes as far as you have defined label locations. It can grow as you define positions for more months.  That's 25 settings variables, which is definitely manageable.

    • Edited by Acamar Thursday, August 20, 2015 9:41 PM sp
    • Marked as answer by grandpaagain Friday, August 21, 2015 8:49 AM
    Thursday, August 20, 2015 9:35 PM
  • Thank you for the additional detail, it is very helpful.

    For something like this I would suggest creating your own data container class to hold the label positions, something like the following code.  In this example the labels are referred to by name, but you could also refer to them by an index number; I'm not sure what is most appropriate as it depends on how the form is actually laid out.

    Option Strict On
    
    Public Class Form1
        Private labelData As New CalendarLabelData
        Private dataPath As String = IO.Path.Combine(My.Application.Info.DirectoryPath, "labels.dat")
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            If IO.File.Exists(dataPath) Then labelData.Load(dataPath)
        End Sub
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            labelData.Save(dataPath)
        End Sub
    End Class
    
    Public Class CalendarLabelData
        Private listCore As New Dictionary(Of MonthYear, Dictionary(Of String, Point))
    
        Public Function GetLocation(year As Integer, month As Integer, labelName As String) As Point
            Dim target As New MonthYear(month, year)
            If Not listCore.ContainsKey(target) Then Return Point.Empty
            If Not listCore(target).ContainsKey(labelName) Then Return Point.Empty
            Return listCore(target)(labelName)
        End Function
    
        Public Sub Load(filePath As String)
            Using fs As IO.FileStream = IO.File.Open(filePath, IO.FileMode.Open)
                Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                listCore = CType(bf.Deserialize(fs), Dictionary(Of MonthYear, Dictionary(Of String, Point)))
            End Using
        End Sub
    
        Public Sub SetLocation(year As Integer, month As Integer, labelName As String, labelLocation As Point)
            Dim target As New MonthYear(month, year)
            If Not listCore.ContainsKey(target) Then listCore.Add(target, New Dictionary(Of String, Point))
            listCore(target)(labelName) = labelLocation
        End Sub
    
        Public Sub Save(filePath As String)
            Using fs As IO.FileStream = IO.File.Open(filePath, IO.FileMode.OpenOrCreate)
                Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter
                bf.Serialize(fs, listCore)
            End Using
        End Sub
    
        <Serializable()>
        Private Structure MonthYear
            Public Month As Integer
            Public Year As Integer
            Public Sub New(m As Integer, y As Integer)
                Month = m
                Year = y
            End Sub
        End Structure
    End Class

    With this example you can call labelData.GetLocation() and pass the year, month, and label name to get the stored position.  The example shows how you can persist the location data to a binary file stored alongside the executable.

    If the 25 labels in question are the only labels in that parent control then you might have a loop something like the following for setting all of the locations:

    Dim year, month As Integer
    'set year and month according to calendar selection
    For Each lbl As Label In Controls.OfType(Of Label)
        lbl.Location = labelData.GetLocation(year, month, lbl.Name)
    Next
    

    Exactly how you go about setting and retrieving the positions depends on the layout of the form (this loop won't work if there are other labels in the same parent besides the 25 in question).


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by grandpaagain Friday, August 21, 2015 8:49 AM
    Thursday, August 20, 2015 10:11 PM
    Moderator
  • Thanks for all your help, I appreciate it.
    Friday, August 21, 2015 11:05 AM