Random programming things I'd want to remember

Monday, December 3, 2012

Today I learned (December 3, 2012)


Today I learned how to access StaticResource resources from xaml.cs codebehind files. This is how I'd return the regular PhoneForegroundBrush color from an IValueConverter:
return App.Current.Resources["PhoneForegroundBrush"] as SolidColorBrush;


And this is how I would emphasize text with the phone accent color.
return App.Current.Resources["PhoneForegroundBrush"] as SolidColorBrush;


Sources: source 1, source 2

Monday, October 15, 2012

Responsive UI while uploading stuff in the background Part 3


In this final post, I will make sure that the form can do work on the background, that it can inform the user about the progress, and that the user can cancel the job at any time. I will build on the code that I posted in parts 1 and 2. At part 2, I left the form fully responsive while it was doing work, but without an ability for the user to cancel work. In order to be able to cancel, I will add a Cancel property to my Uploader class like so:

        public bool Cancel { get; set; }

Then, I will modify my UploadFiles method to check whether the work has been cancelled and quit the upload if needed.

        public void UploadFiles()
        {
            int partTracker = 0;

            if (OnStartingUpload != null) //Here I need number of pieces that will be uploaded
                OnStartingUpload(this, new UploaderEventArgs 
                {  
                    DataToUpload_Length = this.DataToUpload_Length, 
                    NumberOfFilesToUpload = FileNames.Count,
                    PartsToUpload_TotalCount = this.DataToUpload_Length,
                    PartsToUpload_UploadedSoFar = 0
                });

            for (int i = 0; i < FileNames.Count; i++)
            {                
                if (Cancel) 
                    break;

                //Log.UploadingFile(FileNames[i]);
                if (OnStartingFileUpload != null) //here I need the number of pieces in the file that will be uploaded, and file name
                    //OnStartingFileUpload(this, new UploaderEventArgs {NumberOfFilesToUpload=FileNames.Count, FileName = FileNames[i], FileUpload = true, FilePartUpload = false, PartsToUpload = 0, PartsUploaded = 0 });
                    OnStartingFileUpload(this, new FileUploaderEventArgs { FileName = FileNames[i], Cancelled=this.Cancel/*, PartsInFile = FileNames[i].Length*/ });


                for (int k = 0; k < FileNames[i].Length; k++)
                {
                    if (Cancel) 
                        break;
                    //Log.UploadingPartAOfB(k+1, partsPerFile);
                    if (OnStartingFilePartUpload != null) //here I need the number of pieces in the file that were uploaded so far and total number of pieces to upload
                        //OnStartingFilePartUpload(this, new UploaderEventArgs { NumberOfFilesToUpload = FileNames.Count, FileName = FileNames[i], FileUpload = false, FilePartUpload = true, PartsToUpload = partsPerFile, PartsUploaded = k });
                        OnStartingFilePartUpload(this, new FilePartUploaderEventArgs { PartsUploadedSoFar = k, PartsToUpload = FileNames[i].Length, FileName = FileNames[i], Cancelled = this.Cancel });

                    Thread.Sleep(new TimeSpan(partUploadDelayNs*1000));
                    
                    partTracker += 1;

                    //Log.UploadedPartAOfB(k+1, partsPerFile);
                    if (OnFinishedFilePartUpload != null) //here I need the number of pieces in the file that were uploaded so far and total number of pieces to upload
                        //OnFinishedFilePartUpload(this, new UploaderEventArgs { NumberOfFilesToUpload = FileNames.Count, FileName = FileNames[i], FileUpload = false, FilePartUpload = true, PartsToUpload = partsPerFile, PartsUploaded = k });
                        OnFinishedFilePartUpload(this, new FilePartUploaderEventArgs { PartsUploadedSoFar = k + 1, PartsToUpload = FileNames[i].Length, FileName = FileNames[i], Cancelled = this.Cancel });
                }

                if (OnFinishedFileUpload != null) //Here I need the file name
                    //OnFinishedFileUpload(this, new UploaderEventArgs { NumberOfFilesToUpload = FileNames.Count, FileName = FileNames[i], FileUpload = true, FilePartUpload = false, PartsToUpload = 0, PartsUploaded = 0 });
                    OnFinishedFileUpload(this, new FileUploaderEventArgs { FileName = FileNames[i], Cancelled = this.Cancel/*, PartsInFile = FileNames[i].Length*/ });
            }

            if (OnFinishedUpload != null) //Here I need the number of files uploaded
                OnFinishedUpload(this, new UploaderEventArgs { NumberOfFilesToUpload = FileNames.Count, Cancelled = this.Cancel });
        }

Since I also notify about cancellation in the raised events, I need to update the EventArgs classes:

    public class FileUploaderEventArgs : EventArgs
    { 
        public string FileName { get; set; }
        public bool Cancelled { get; set; }
        //public int PartsInFile { get; set; }
    }

    public class FilePartUploaderEventArgs : EventArgs
    {
        //Number of parts uploaded so far, total number of parts to upload
        public int PartsUploadedSoFar { get; set; }
        public int PartsToUpload { get; set; }
        public string FileName { get; set; }
        public bool Cancelled { get; set; }
    }

    public class UploaderEventArgs : EventArgs
    {
        public int PartsToUpload_TotalCount { get; set; }
        public int PartsToUpload_UploadedSoFar { get; set; }

        public int DataToUpload_Length { get; set; }
        public int DataToUpload_Uploaded { get; set; }
        public int NumberOfFilesToUpload { get; set; }

        public string FileName { get; set; }
        public int PartsToUpload { get; set; }
        public int PartsUploaded { get; set; }

        public bool FileUpload { get; set; }
        public bool FilePartUpload { get; set; }
        public bool Cancelled { get; set; }
    }

Finally, in the stop button event handler, I need to set the Cancel property of the Uploader global variable to true:

        private void stopButton_Click(object sender, RoutedEventArgs e)
        {
            u.Cancel = true;

            if (bg1.IsBusy)
                bg1.CancelAsync();

            overallStatusLabel.Content = "Cancelling upload";
        }

And now I have a template for a work that is done on the background that can be cancelled at any time.

Thursday, October 11, 2012

Responsive UI while uploading stuff in the background Part 2


In my previous post, I showed a program that is supposed to be doing stuff on the background, even though it was not updating the UI. In this post, I will show how to make it so that we can see the changes in the UI while the program is doing its magic.

Most of the program stayed the same, the only difference is in the MainWindow.xaml.cs. The secret weapon here is System.ComponentModel.BackgroundWorker. To successfully launch a background worker, put the time-consuming operation into the code for the worker's DoWork event. I need the interface updates here, and since my Uploader class is doing time-consuming work on another thread, I wrapped up the calls for the UI update into the Dispatcher.BeginInvoke(... code blocks. The only thing that is not working here is the event for the Stop button. It calls the background worker's CancelAsync() method, but the Uploader class cannot interrupt its actions. I will show a way to fix that in the next post.

    public partial class MainWindow : Window
    {
        Stopwatch s = new Stopwatch();
        Uploader u = new Uploader();
        BackgroundWorker bg1 = new BackgroundWorker();

        public MainWindow()
        {
            InitializeComponent();
            InitializeUploaderEvents();
            InitializeBackgroundWorker();
        }

        public void InitializeUploaderEvents()
        {
            u.OnStartingUpload += new StartingUpload(u_OnStartingUpload);
            u.OnFinishedUpload += new FinishedUpload(u_OnFinishedUpload);
            u.OnStartingFileUpload += new StartingFileUpload(u_OnStartingFileUpload);
            u.OnFinishedFileUpload += new FinishedFileUpload(u_OnFinishedFileUpload);
            u.OnStartingFilePartUpload += new StartingFilePartUpload(u_OnStartingFilePartUpload);
            u.OnFinishedFilePartUpload += new FinishedFilePartUpload(u_OnFinishedFilePartUpload);
        }

        private void InitializeBackgroundWorker()
        {
            bg1.DoWork += new DoWorkEventHandler(bg1_DoWork);
            bg1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg1_RunWorkerCompleted);
            bg1.WorkerReportsProgress = true;
            bg1.WorkerSupportsCancellation = true;
        }

        void bg1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
                MessageBox.Show(e.Error.Message);
            else if (e.Cancelled)
                overallStatusLabel.Content = "Upload cancelled";
            else
            {
                overallStatusLabel.Content = String.Format("Upload finished successfully, took {0} ", s.Elapsed);
            }
        }

        void bg1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker b = sender as BackgroundWorker;
            Uploader u1 = e.Argument as Uploader; //I am not using this variable yet

            u.UploadFiles();
        }
        
        void u_OnStartingFilePartUpload(object source, FilePartUploaderEventArgs e)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            {
                currentFileStatusLabel.Content = String.Format("Uploading file {0}, {1}/{2} parts done.", e.FileName, e.PartsUploadedSoFar, e.PartsToUpload);
                fileUploadProgressBar.Maximum = e.PartsToUpload;
                fileUploadProgressBar.Value = e.PartsUploadedSoFar;
            });
        }

        void u_OnFinishedFilePartUpload(object source, FilePartUploaderEventArgs e)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
             {
                 currentFileStatusLabel.Content = String.Format("Uploading file {0}, {1}/{2} parts done.", e.FileName, e.PartsUploadedSoFar, e.PartsToUpload);
                 progressBar1.Value += 1;
                 fileUploadProgressBar.Maximum = e.PartsToUpload;
                 fileUploadProgressBar.Value = e.PartsUploadedSoFar;
             });
        }

        void u_OnStartingFileUpload(object source, FileUploaderEventArgs e)
        {
           Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            { 
                currentFileStatusLabel.Content = String.Format("Starting to upload file {0}", e.FileName); 
            });
        }

        void u_OnFinishedFileUpload(object source, FileUploaderEventArgs e)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            {
                currentFileStatusLabel.Content = String.Format("Finished uploading file {0}", e.FileName); 
            });
        }

        private void startButton_Click(object sender, RoutedEventArgs e)
        {
            progressBar1.Maximum = u.DataToUpload_Length;
            progressBar1.Value = 0;
            bg1.RunWorkerAsync();
        }

        void u_OnFinishedUpload(object source, UploaderEventArgs e)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
               {
                   s.Stop();
                   overallStatusLabel.Content = String.Format("Finished uploading {0} files, elapsed time: {1}", e.NumberOfFilesToUpload, s.Elapsed);
               });
        }

        void u_OnStartingUpload(object source, UploaderEventArgs e)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            {
                overallStatusLabel.Content = String.Format("Started uploading {0} files", e.NumberOfFilesToUpload);
                progressBar1.Maximum = e.PartsToUpload_TotalCount;
                progressBar1.Value = e.PartsToUpload_UploadedSoFar; //0
                s.Start();
            });
        }

        private void stopButton_Click(object sender, RoutedEventArgs e)
        {
            if (bg1.IsBusy)
                bg1.CancelAsync();

            overallStatusLabel.Content = "Cancelling upload";
        }
    }


Monday, October 8, 2012

Responsive UI while uploading stuff in the background part 1


I was working on a program that required multiple uploads to be done in the background while updating the progress status for the user. I decided to go with WPF and C#. In this post, I will provide an outline for the program that simulates the upload without updating the interface. In the next posts I will explain how to update the UI and provide mechanisms to cancel uploads. Let's start with the interface:

<Window x:Class="BackgroundWorkerExperiment.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Button x:Name="startButton" Content="Start" Click="startButton_Click" Margin="5" />
        <Button x:Name="stopButton" Content="Stop" Click="stopButton_Click" Grid.Row="1" Margin="5" />
        <StackPanel Orientation="Horizontal" Grid.Row="2">
            <ProgressBar x:Name="progressBar1" Margin="5" Width="150" />
            <Label x:Name="overallStatusLabel" Margin="5" />
        </StackPanel>
        <StackPanel Orientation="Horizontal" Grid.Row="3">
            <ProgressBar x:Name="fileUploadProgressBar" Margin="5" Width="150" />
            <Label x:Name="currentFileStatusLabel" Margin="5" />
        </StackPanel>
    </Grid>
</Window>

Pretty simple form. Next, the class with helper methods that would "generate" some files:

    public static class Helpers
    {
        private static List<char> CharacterVocabulary_Get()
        {
            List<char> vocabulary = new List<char>();

            for (int i = 48; i <= 57; i++)
            {
                char a = (char)(i);
                vocabulary.Add(a);
            }

            for (int i = 64; i < 90; i++)
            {
                char a = (char)(i);
                vocabulary.Add(a);
            }
            for (int i = 97; i <= 122; i++)
            {
                char a = (char)(i);
                vocabulary.Add(a);
            }

            return vocabulary;
        }

        public static List<string> GetListOfNStringsOfKLength(int stringCount, int stringLength)
        {
            List<string> result = new List<string>();

            Random r = new Random();
            List<char> characters = CharacterVocabulary_Get();            

            for (int k = 1; k <= stringCount; k++)
            {
                StringBuilder sb = new StringBuilder(k.ToString(), stringLength+1);

                for (int j = 0; j < stringLength; j++)
                {
                    sb.Append(characters[r.Next(characters.Count)]);

                }
                result.Add(sb.ToString());
            }

            return result;
        }

        public static List<string> GetListOfNStringsOfVariableLength(int stringCount, int minStringLength, int maxStringLength)
        {
            List<string> result = new List<string>();

            Random r = new Random();
            List<char> characters = CharacterVocabulary_Get();

            for (int k = 1; k <= stringCount; k++)
            {
                int strLength = r.Next(minStringLength, maxStringLength);

                StringBuilder sb = new StringBuilder(k.ToString(), strLength+1);

                for (int j = 0; j < strLength; j++)
                {
                    sb.Append(characters[r.Next(characters.Count)]);

                }
                result.Add(sb.ToString());
            }
            return result;
        }

    }

Now, the class that does the simulated upload. It may look complex, but it has a lot of events that it raises before and after each of the meaningful states. First, the class signals that it starts the uploading process. Then, it signals that it starts uploading a certain file. Then, it signals that it starts uploading a part of that file. Then, after some time, it signals that it finished uploading the part of the file. The class also lets its user know that it finished uploading a file, and it finished uploading everything.

    public delegate void StartingUpload(object source, UploaderEventArgs e);
    public delegate void FinishedUpload(object source, UploaderEventArgs e);

    public delegate void StartingFileUpload(object source, FileUploaderEventArgs e);
    public delegate void FinishedFileUpload(object source, FileUploaderEventArgs e);

    public delegate void StartingFilePartUpload(object source, FilePartUploaderEventArgs e);
    public delegate void FinishedFilePartUpload(object source, FilePartUploaderEventArgs e);

    class Uploader
    {
        public List<string> FileNames { get; set; }
        public int DataToUpload_Length
        {
            get
            {
                int ret = 0;
                if (FileNames == null)
                    return ret;
                else
                {
                    foreach (string s in FileNames)
                    {
                        ret += s.Length;
                    }
                    return ret;
                }
            }
        }

        private int partsPerFile = 5;
        private long partUploadDelayNs = 10000;

        public event StartingUpload OnStartingUpload;
        public event FinishedUpload OnFinishedUpload;

        public event StartingFileUpload OnStartingFileUpload;
        public event FinishedFileUpload OnFinishedFileUpload;

        public event StartingFilePartUpload OnStartingFilePartUpload;
        public event FinishedFilePartUpload OnFinishedFilePartUpload;

        public Uploader()
        {
            FileNames = Helpers.GetListOfNStringsOfVariableLength(5, 8, 15);
        }

        public Uploader(List<string> fileNames)
        {
            FileNames = fileNames;
        }

        public void UploadFiles()
        {
            int partTracker = 0;

            if (OnStartingUpload != null) //Here I need number of pieces that will be uploaded
                OnStartingUpload(this, new UploaderEventArgs 
                {  
                    DataToUpload_Length = this.DataToUpload_Length, 
                    NumberOfFilesToUpload = FileNames.Count,
                    PartsToUpload_TotalCount = this.DataToUpload_Length,
                    PartsToUpload_UploadedSoFar = 0
                });

            for (int i = 0; i < FileNames.Count; i++)
            {
                //Log.UploadingFile(FileNames[i]);
                if (OnStartingFileUpload != null) //here I need the number of pieces in the file that will be uploaded, and file name
                    OnStartingFileUpload(this, new FileUploaderEventArgs { FileName = FileNames[i]/*, PartsInFile = FileNames[i].Length*/ });

                for (int k = 0; k < partsPerFile; k++)
                {
                    //Log.UploadingPartAOfB(k+1, partsPerFile);
                    if (OnStartingFilePartUpload != null) //here I need the number of pieces in the file that were uploaded so far and total number of pieces to upload
                        OnStartingFilePartUpload(this, new FilePartUploaderEventArgs { PartsUploadedSoFar = k, PartsToUpload = FileNames[i].Length, FileName = FileNames[i] });

                    Thread.Sleep(new TimeSpan(partUploadDelayNs*100));
                    
                    partTracker += 1;

                    //Log.UploadedPartAOfB(k+1, partsPerFile);
                    if (OnFinishedFilePartUpload != null) //here I need the number of pieces in the file that were uploaded so far and total number of pieces to upload
                        OnFinishedFilePartUpload(this, new FilePartUploaderEventArgs { PartsUploadedSoFar = k + 1, PartsToUpload = FileNames[i].Length, FileName = FileNames[i] });
                }

                if (OnFinishedFileUpload != null) //Here I need the file name
                     OnFinishedFileUpload(this, new FileUploaderEventArgs { FileName = FileNames[i]/*, PartsInFile = FileNames[i].Length*/ });
            }

            if (OnFinishedUpload != null) //Here I need the number of files uploaded
                OnFinishedUpload(this, new UploaderEventArgs { NumberOfFilesToUpload = FileNames.Count });
        }
    }

    public class FileUploaderEventArgs : EventArgs
    { 
        public string FileName { get; set; }
    }

    public class FilePartUploaderEventArgs : EventArgs
    {
        public int PartsUploadedSoFar { get; set; }
        public int PartsToUpload { get; set; }
        public string FileName { get; set; }
    }

    public class UploaderEventArgs : EventArgs
    {
        public int PartsToUpload_TotalCount { get; set; }
        public int PartsToUpload_UploadedSoFar { get; set; }

        public int DataToUpload_Length { get; set; }
        public int DataToUpload_Uploaded { get; set; }
        public int NumberOfFilesToUpload { get; set; }

        public string FileName { get; set; }
        public int PartsToUpload { get; set; }
        public int PartsUploaded { get; set; }

        public bool FileUpload { get; set; }
        public bool FilePartUpload { get; set; }
    }

And now it is time to look at the code behind the main form. Nothing fancy here either. Wire up the Uploader class, let the user know what's happening in the events that it raises, make sure the start button initializes the simulation.

    public partial class MainWindow : Window
    {
        Stopwatch s = new Stopwatch();
        Uploader u = new Uploader();

        public MainWindow()
        {
            InitializeComponent();
            InitializeUploaderEvents();
        }

        public void InitializeUploaderEvents()
        {
            u.OnStartingUpload += new StartingUpload(u_OnStartingUpload);
            u.OnFinishedUpload += new FinishedUpload(u_OnFinishedUpload);
            u.OnStartingFileUpload += new StartingFileUpload(u_OnStartingFileUpload);
            u.OnFinishedFileUpload += new FinishedFileUpload(u_OnFinishedFileUpload);
            u.OnStartingFilePartUpload += new StartingFilePartUpload(u_OnStartingFilePartUpload);
            u.OnFinishedFilePartUpload += new FinishedFilePartUpload(u_OnFinishedFilePartUpload);
        }
        
        void u_OnStartingFilePartUpload(object source, FilePartUploaderEventArgs e)
        {
            currentFileStatusLabel.Content = String.Format("Uploading file {0}, {1}/{2} parts done.", e.FileName, e.PartsUploadedSoFar, e.PartsToUpload);
        }

        void u_OnFinishedFilePartUpload(object source, FilePartUploaderEventArgs e)
        {
            currentFileStatusLabel.Content = String.Format("Uploading file {0}, {1}/{2} parts done.", e.FileName, e.PartsUploadedSoFar, e.PartsToUpload);
        }

        void u_OnStartingFileUpload(object source, FileUploaderEventArgs e)
        {
            currentFileStatusLabel.Content = String.Format("Starting to upload file {0}", e.FileName);
        }

        void u_OnFinishedFileUpload(object source, FileUploaderEventArgs e)
        {
            currentFileStatusLabel.Content = String.Format("Finished uploading file {0}", e.FileName);
        }

        private void startButton_Click(object sender, RoutedEventArgs e)
        {
            progressBar1.Maximum = u.DataToUpload_Length;
            progressBar1.Value = 0;
            u.UploadFiles();
        }

        void u_OnFinishedUpload(object source, UploaderEventArgs e)
        {
            s.Stop();
            overallStatusLabel.Content = String.Format("Finished uploading {0} files, elapsed time: {1}", e.NumberOfFilesToUpload, s.Elapsed);
        }

        void u_OnStartingUpload(object source, UploaderEventArgs e)
        {
            overallStatusLabel.Content = String.Format("Started uploading {0} files", e.NumberOfFilesToUpload);
            progressBar1.Maximum = e.PartsToUpload_TotalCount;
            progressBar1.Value = e.PartsToUpload_UploadedSoFar; //0
            s.Start();
        }

        private void stopButton_Click(object sender, RoutedEventArgs e)
        {

        }
    }

However, if you put this all together and hit the start button, there will be no feedback. The form will freeze and after a while it will unfreeze letting you know that the upload finished, but without letting you know what was happening during the upload process. Stay tuned on how to fix this.

Monday, July 30, 2012

Solving the size limitation of controls in Windows Phone 7


There is a limitation on a size of a control in Windows Phone 7 of 2048 pixels, and I needed to sometimes display a long list of items. Here is how I did that. First off, the XAML portion:

<ScrollViewer Tap="ScrollViewer_Tap" Name="AnswerScrollViewer" 
                          Grid.Row="1" Height="Auto">
    <StackPanel x:Name="AnswerScrollViewerStackPanel">
        <TextBlock x:Name="Answer"  
                      Width="430"
                      Text=""
                      Tag=""
                      FontSize="28" 
                      TextWrapping="Wrap" />
    </StackPanel>
</ScrollViewer>

There is a ScrollViewer that I use to scroll a long list. It has a StackPanel (because ScrollViewer can only have one control inside it, and I will use several controls to display a long list of text). Then the StackPanel has the "Answer" TextBlock control that is used when there is no need to display the long list.

And now, on to the magic. This is a part of the function that assigns the text to the text block.


//more on the MeasureSizeOfATextBlock() later
double futureAnswerTextBlockSize = MeasureSizeOfATextBlock(Answer, Answer.Tag.ToString());

//MAXCONTROLHEIGHT is a constant, close to 2048
if (futureAnswerTextBlockSize > MAXCONTROLHEIGHT)
{    //I split my string by the carriage returns
    string[] options = { "\r\n" };
    string[] arr = Answer.Tag.ToString().Split(options, StringSplitOptions.None);

//Let's create the first text block to start displaying the list
    TextBlock b = new TextBlock();
    b.Foreground = DarkThemeIsVisible() //more on this function later
        ? new SolidColorBrush(Color.FromArgb(255, 255, 255, 255))
        : new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
    b.VerticalAlignment = System.Windows.VerticalAlignment.Top;
    b.FontSize = ANSWERTEXTFONTSIZE;
    b.TextWrapping = TextWrapping.Wrap;
    b.Width = 430;
    b.Name = "sb1"; //the name really does not matter

    int j = 0;
//This constant will help me omit the new line before the first line of text
    bool omitCRForNewLine = true;
//and let's display the text
    while (j < arr.Length)
    {
        if (!omitCRForNewLine)
            b.Text += Environment.NewLine + arr[j];
        else
            b.Text += arr[j];

        omitCRForNewLine = false;

        j += 1;
        if (b.ActualHeight > MAXCONTROLHEIGHT - 20)
        { //The height of the control is getting closer to the limit
//so let's add this control to the stack panel, and ...
            AnswerScrollViewerStackPanel.Children.Add(b);
//create a new control to continue displaying the text
            b = new TextBlock();
            b.Foreground = DarkThemeIsVisible()
                ? new SolidColorBrush(Color.FromArgb(255, 255, 255, 255))
                : new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
            b.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            b.FontSize = ANSWERTEXTFONTSIZE;
            b.TextWrapping = TextWrapping.Wrap;
            b.Width = 430;
            b.Name = "sb" + j.ToString();
//reset this variable to avoid the empty line in the beginning
            omitCRForNewLine = true; 
        }

        if (j == arr.Length - 1) //add the last text block
            AnswerScrollViewerStackPanel.Children.Add(b);

    } //hide Answer text block, I am not using it
    Answer.Visibility = System.Windows.Visibility.Collapsed;
}
else
{ //if one text block is enough, everything is simple
    Answer.Visibility = System.Windows.Visibility.Visible;
    Answer.Text = Answer.Tag.ToString();

    Answer.Foreground = DarkThemeIsVisible()
        ? new SolidColorBrush(Color.FromArgb(255, 255, 255, 255))
        : new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
    Answer.VerticalAlignment = System.Windows.VerticalAlignment.Top;

    Answer.FontSize = ANSWERTEXTFONTSIZE;
}


And here are the two helper functions. The first function takes a control as input, and a line of text. Then it creates a TextBlock, assigns some parameters and returns the ActualHeight parameter of the control.

private double MeasureSizeOfATextBlock(TextBlock t, string text)
{
    TextBlock a = new TextBlock();
    a.Width = t.Width;
    a.FontFamily = t.FontFamily;
    a.FontStyle = t.FontStyle;
    a.FontWeight = t.FontWeight;
    a.FontSize = t.FontSize;
    a.Text = text;
    a.TextWrapping = t.TextWrapping;

    return a.ActualHeight;
}



This function determines whether the user has the dark or light theme selected.

private bool DarkThemeIsVisible()
{
    Visibility v = (Visibility)Resources["PhoneDarkThemeVisibility"];
    if (v == System.Windows.Visibility.Visible)
        return true;

    return false;
}




Friday, July 20, 2012

Windows Phone 7 ItemsControl within an ItemsControl, solving slow loading issue


So it happened that I needed to show a long list within a long list. I found that the scrolling performance of a ListBox was not up to par, so I tried an ItemsControl. Here is the XAML:


<ItemsControl 
    MaxWidth="450" VirtualizingStackPanel.VirtualizationMode="Recycling"
    ItemsSource="{Binding AnswersForDisplayAsAListBySomeNumberOfElements}"
    Visibility="{Binding ThisOneHasALongAnswer, Converter={StaticResource showLongAnswer}}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <<ItemsControl.Template>
        <ControlTemplate>
            <ScrollViewer x:Name="InnerScrollViewer" Padding="{TemplateBinding Padding}" MaxHeight="400">
                <ItemsPresenter />
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" TextWrapping="Wrap" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Upon binding, if the ItemsList is visible, it displays a scrollable list. The problem with this approach is that once the inner list is scrolled to the bottom (or to the top), the outer ItemsList is not being scrolled. After playing with it for a bit, I figured out that if the ScrollViewer is removed from the ItemsControl.Template part of the control declaration, then the long list is displayed in its entire height and scrolling the individual item scrolls the entire outer ItemsList

Sunday, July 15, 2012

Extract data from an app in Windows Phone 7


I needed to export some text data out of one Windows Phone 7 application. I did not care for the format, so I thought e-mailing data to myself would be just fine. Here is some code. First, let's build the data:

public StringBuilder GetData()
{
  StringBuilder result = new StringBuilder();

  List<InventoryItem> a = ReadInventoryItems().OrderBy(x=>x.SerialNumber).OrderBy(x => x.Account).Where(x => x.isFound == true).ToList<InventoryItem>();

  foreach (InventoryItem i in a)
  {
    LocatedItem l = new LocatedItem { 
        Account = i.Account, 
        SerialNo = i.SerialNumber, 
        wasFound = i.isFound, 
        withNote = i.Note 
    };
    result.Append(l.ToString() + Environment.NewLine);
  }
  return result;
}



InventoryItem and LocatedItem are just two classes that I use to store data:
public class InventoryItem
{
    public string SerialNumber { get; set; }
    public string Account { get; set; }
    public string ModelDesc { get; set; }
    public string Building { get; set; }
    public string Room { get; set; }
    public string BuildingRoom { get; set; }
    public bool isFound { get; set; }
    public string Note { get; set; }
}

 public class LocatedItem
 {
     public string Account {get; set;}
     public string SerialNo { get; set; }
     public bool wasFound { get; set; }
     public string withNote { get; set; }

     public override string ToString()
     {
         return String.Format("{0} {1} {2} {3}", Account, SerialNo, wasFound == true ? "1" : "0", withNote);
     }
 }


Data is ready, how to extract it? The help comes from EmailComposeTask class that resides is the Microsoft.Phone.Tasks namespace. Here is some code:
EmailComposeTask email = new EmailComposeTask();
emailcomposer.To = @"youraddress@yourmailserver.com";
emailcomposer.Subject = "test subject";
DataLayer dl = new DataLayer();
emailcomposer.Body = dl.GetAllFoundItems().ToString();
emailcomposer.Show();


And that is it! Once deployed to the phone, choose the e-mail provider that will send the message and send the e-mail.

Wednesday, May 2, 2012

How to dynamically add a Border around TextBlock in Silverlight





TextBlock b = new TextBlock();
b.VerticalAlignment = System.Windows.VerticalAlignment.Top;
b.FontSize = 28;
b.TextWrapping = TextWrapping.Wrap;
b.Width = 430;
b.Text = "Hello World!";

Border a = new Border();
a.BorderThickness = new Thickness(2);
a.BorderBrush = new SolidColorBrush(Colors.Blue);
a.Child = b;

Monday, April 30, 2012

How to add Run control dynamically




textBlock.Inlines.Clear();
textBlock.Inlines.Add(new Run() { Text = Answer.Tag.ToString() });



Wednesday, April 11, 2012

How to display more than 1 text fragment on the same line using XAML

If using TextBlock, use Text.Inlines property. That can help do things like this:

<TextBlock TextWrapping="Wrap">
    <TextBlock.Inlines>
        <Run FontWeight="Bold" Text="And" />
        <Run Text=" then..." />
    </TextBlock.Inlines>
</TextBlock>


Which will look like:
And then...

If there is a need to use different types of controls, then one could use the Grid control like so:

<Grid x:Name="grid1>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="300" />
    <ColumnDefinition Width="*"/>
  </Grid.ColumnDefinitions>
  
  <TextBlock x:Name="txtBlock1" Width="260" Grid.Column="0" Text="Text" />
  <TextBox x:Name="txtBox1" Text="a" Width="120" Grid.Column="1"></TextBox>
</Grid>

Monday, March 26, 2012

How to spell ti and di in katakana/Как написать "ти" и "ди" катаканой.

てぃ,ティ:
Type "texi" или "thi", no spaces, no quotes.
Печатайте "texi" или "thi", без кавычек.

でぃ,ディ:
Type "dexi" или "dhi", no spaces, no quotes.
Печатайте "dexi" или "dhi", без кавычек.

Sunday, March 25, 2012

How to order a collection by a custom property

Suppose you have the following code:

public class TestItem { public string Name { get; set; } public int Count { get; set; } } public partial class MainPage : PhoneApplicationPage { // Constructor public MainPage() { InitializeComponent(); List<TestItem> li = new List<TestItem>(); TestItem a = new TestItem { Name = "First name", Count = 1 }; TestItem b = new TestItem { Name = "Second name", Count = 3 }; TestItem c = new TestItem { Name = "Third name", Count = 2 }; //But how do I order the items in the collection by Count property? listBox1.DataContext = li; } }
If I want to order the collection before binding it to the listbox, how do you do that? This is how:

li.Sort((a, b) => a.SortingParam.CompareTo(b.SortingParam));

Wednesday, March 21, 2012

Error: To generate an event handler the class 'MainPage', specified by the x:Class or x:Subclass...

I was testing something out on the Windows Phone 7 platform and, when tried to add a button Click event, Visual Studio 2010 gave me the following error: To generate an event handler the class 'MainPage', specified by the x:Class or x:Subclass attribute, must be the first class in the file. Move the class code so that it is the first class in the file and try again. This is what my MainPage.xaml.cs file looked like:

public class TestItem { public string Name { get; set; } public int Count { get; set; } } public partial class MainPage : PhoneApplicationPage { // Constructor public MainPage() { InitializeComponent(); List<TestItem> li = new List<TestItem>(); TestItem a = new TestItem { Name = "First name", Count = 1 }; TestItem b = new TestItem { Name = "Second name", Count = 2 }; TestItem c = new TestItem { Name = "Third name", Count = 3 }; listBox1.DataContext = li; } }
Then I realized that I put together a dummy class to test binding on a ListBox and put it on the top of the document. Once I moved the TestItem class definition down, the page compiled and I was able to add events from the XAML page. Here is what the working code looks like:

public partial class MainPage : PhoneApplicationPage { // Constructor public MainPage() { InitializeComponent(); List<TestItem> li = new List<TestItem>(); TestItem a = new TestItem { Name = "First name", Count = 1 }; TestItem b = new TestItem { Name = "Second name", Count = 2 }; TestItem c = new TestItem { Name = "Third name", Count = 3 }; listBox1.DataContext = li; } private void btn1_Click(object sender, RoutedEventArgs e) { } } public class TestItem { public string Name { get; set; } public int Count { get; set; } }

Friday, March 16, 2012

Scanning computer with Clam antivirus using System Rescue CD

System Rescue CD (SRCD) has recently become a very important tool in my IT specialist toolbox. Not only this is a live Linux CD with all the goodies (such as gparted, Windows registry editor and so on), it also packs some command-line tools, such as the NTPASSWD utility, or a utility to edit the master boot record on a hard drive.  This post will describe the process of scanning a drive for viruses using Clam Anti-Virus.

1. Boot into SRCD, option 1.
2. Enter (for default keyboard time)v
3. Net-setup eth0 , press Enter
4. Yes
5. 2 (Wired)
6. 1 (DHCP)
7. ifconfig (to check for an ip address)
8. freshclam (this command pulls the updated virus definitons from the server)
9. fdisk -l (that is an L)
10. ntfs3g /dev/sda1 /mnt/windows
11. clamscan (--help)
12. clamscan -r /mnt/windows

Wednesday, March 7, 2012

Objective-C: Imitation of C# "String.Contains()" method

The method returns a YES or a NO:

Method signature:
- (BOOL) containsString:(NSString *) string
                options:(NSStringCompareOptions) options;

Method body:
- (BOOL) containsString:(NSString *) string
                options:(NSStringCompareOptions) options {
    NSRange rng = [self rangeOfString:string options:options];
    return rng.location != NSNotFound;
}

If NSStringCompareOptions make no difference, a 0 can be passed to the method.

Tuesday, March 6, 2012

Windows phone review after a month of use by an iPhone user (Samsung SGH-i917)


I have a Samsung SGH-i917 (a Windows 7 phone) and I would like to share my experience of using it in case someone is thinking about getting a Windows 7 phone. For the record, I have used an iPhone for several years and it influenced my mobile phone usage. I am not, in any way, against Windows 7 Phone platform, I just want to point out things that could use some more work.

Turning on the phone. This phone is light and thin, which makes it harder to find the power button, and that is the only way to turn on the phone or wake it up. It is hard to tell in the dark which way is up or down, that may increase the time needed to find the power button.

E-mail setup. For some reason, I have to set up the phone with a Windows Live ID. I have an old e-mail associated with Windows Live ID, it has a lot of my old contacts. The phone insisted that I associate a Live ID with it. Ok, I did that. It immediately imported all my contacts from that phone. It would be nice if the phone asked me if I want all those contacts imported. Now I am stuck with a long list of people in my phone that I no longer even talk to. Setting up additional e-mails is very easy. Getting rid of e-mail accounts is a bit tricky. First of all, I cannot get rid of the Live ID e-mail account. Second, if I need to get rid of any other e-mail, I had to click and hold the e-mail account to get the context menu. It took me a bit to figure that out, it would be nice to have a hint or buttons on the bottom. Also, with e-mail (I tried hotmail and gmail), if I delete an e-mail on the phone, it would still be in the mailbox once I use the computer to log in. A matter of preference, really.

Adding a phone contact. This process is the most frustrating for me. I usually type the phone number, press save, expect to type in the name and maybe some other info and then I am done. Here are the steps that one need to take to save a phone number on Windows 7 Phone:
1. Type in the phone number (ok so far).
2. Hit save button. Boom! I suddenly see my contact list. Why? Oh, they assume that my friends buy new phone numbers every week. No, actually my contacts are pretty conservative on their phone numbers. So how do I add a new number? Oh, there is a small plus button on the bottom.
3. Press the + button on the bottom.
4. I see the phone number box, I see the type of the phone. Where do I type in the name? And the number keyboard takes up half the screen. But I already typed in the number! Oh, there is a button on the bottom that looks like a … floppy disk? Who remembers what those are anymore?
5. Let's hit the "floppy disk" button. I see the page, big box to add photo, I see a label for the name, mobile phone (and the phone itself is in the tiny numbers, so if I fat-fingered it, no way I can notice the mistake), phone, email, … how do I type in stuff? Oh, there is a "plus" button to the left of each label, while I was expecting a text box…
6. Let's hit the "plus" button. Yay! I can type in the name! And the floppy disk icon on the button again… oh, they used it to save data before, that symbol must mean "save"!
7. Type the name
8. Hit the floppy disk button to save the name
9. Hit the floppy disk button to save the contact
10. Yay, I saved a contact! The phone number is still small, but it is a very important piece of info.

One contact, but I had to hit save button four times! My ideal way to save a contact is the following:

1. Type in the phone number
2. Hit save button
3. Get presented with fields for the new contact (phone number must be in BIG numbers so that I can double-check it with whoever is giving it to me). If I need to add the phone number to an existing contact, give me a button in top right corner. 
4. Fill in all the info
5. Hit save button.

Wi-Fi. I hooked up the phone to wireless internet, that was easy. However, the phone only displays the Wi-Fi connection icon on the home screen. When I am browsing Internet, I don't see the Wi-Fi icon and I am not sure whether I use my cellular plan or Wi-Fi to get that web page. Same with e-mail. It just says "Syncing", but does not show what connection it uses. This matters for me, I was using a prepaid cell phone plan, did not want to run out of money.

Battery indicator. The phone has information on the remaining battery in percents, as well as approximate time of service remaining until it absolutely needs to be charged. The battery icon in top right, however, cannot be customized to display percents. This is also a matter of preference, but I would prefer to see the percentage of remaining battery power.

Search. The built-in search feature is mostly nice. If I search for "weather" it gives me weather at a glance in my location. But when I try searching for "las vegas weather" (I am not in Las Vegas), it gets stuck searching. I tried restarting search and still no answer. Why? Not sure. May be this is a hardware issue. The other nice feature is built-in search for music, scanner, and voice-activated search. However, there are still issues here. I was listening to the radio and used the "search for music" feature. The radio kept playing and the phone kept listening. I cancelled the searched after about a minute. I sure wasn't turning the radio off. Text/barcode/QR code scanner works great. Oh, one other thing on the search: splitting results into web/local/images, what is "local" supposed to be? I am searching for "weather", swipe to local and I see a small piece of map (I can't make out what that location is, anyway, the map is too small), and the map points to the place called "Time Temperature & Weather". Not sure what it is. Works somewhat better when I search for "farmers market", the results make a bit more sense.

Maps, directions. There are two issues here. First, after I found my route and just want to browse the map along the way, the map keeps returning me where it thinks I am at at the moment. I just want to browse the map before I drive, to see the traffic and other things, don't change my map! The other thing about this area is that once I get directions to some place and hit the back button, directions disappear. That is ok. Another scenario: I find directions, move the maps application to the background, then start it again and hit the back button, what happens? Right, instead of clearing the directions from the map, the phone shows me the screen that I was at before.

Buttons. Home key, once pressed, provides slight vibration feedback; nice feature.

Size. The phone feels wide, thin and light.

Camera. Nice camera, takes good pictures, have some additional features, such as effects and even the white balance correction.

Marketplace. Feels cluttered. When I am choosing an item, I would like to see how much it costs right away, without having to tap on it.

Overall, I think this phone and the platform itself could use some more work. Great job on the concept though, I very much like the fact that I can use C# and put my programs right on to the phone.

Saturday, March 3, 2012

XCode 4.2: how to provide arguments to a command-line app

Here is how to provide arguments to a program in XCode 4.2:
Product -> Edit Scheme

Click on "Run" in the left-side part of the dialog box. If needed, switch to "Arguments" tab in the middle part of the dialog box. Under "Arguments Passed On Launch", press "+" and add a value. Then you can access the value using the following code:
NSProcessInfo *proc = [NSProcessInfo processInfo];
NSArray *args = [proc arguments];
NSString *myArg = [args objectAtPosition: 1];

One note worth mentioning: if your argument contains spaces, enclose it in quotes: "my argument".

Thursday, March 1, 2012

Compile Objective-C code From Terminal With ARC Using xcodebuild

I was perfectly happy compiling Objective-C from the command line until I hit a snag. As a result, I found out about xcodebuild from Joshua Smith . I am still in the process of researching this tool, but so far I use it this way:

xcodebuild -project yourprojectname.xcodeproj -alltargets


and then I use the
./yourprojectname 

command to start the app (I can customize the name of the executable in the project settings).

One thing to note: the xcodebuild command needs the .xcodeproj file to run, so you need to provide the path to the .xcodeproj file when issuing the command.

Wednesday, February 29, 2012

Changing current directory with NSFileManager




NSFileManager *fm;

fm = [NSFileManager defaultManager];


if ([fm changeCurrentDirectoryPath: @"/Users/yourUserNameHere/Documents/folder1/folder2"] == NO)
   NSLog (@"Something went wrong");
//if you don't see the "Something went wrong" message, then the current directory has beed changed, here is how to check it:

NSLog(@"%@", [fm currentDirectoryPath]);




Taking screenshots on a Mac

Tuesday, February 28, 2012

Where XCode keeps compiled files

If using XCode (4.2) and needing to work with path-sensitive code, here is how you can find out where the executables are kept:

File -> Project Settings...

Then click the little arrow by the path under "Derived Data Location" (closer to Advanced button in XCode 4.2). There you will see folders with compiled files. If needed to add some path-sensitive data, insert it under the following path:

Project Name + some gibberish/Build/Products/Debug

Monday, February 27, 2012

Compile Objective-C code From Terminal With ARC Using Clang

In order to compile Objective-C in the terminal, here is what needs to be done: 1. Open Terminal window 2. If using XCode to get the autocompletion and syntax highlighting, navigate to the project folder (using "cd" commands to change directory and "ls" command to see what's in the current folder; use "cd .." to go up one level if went somewhere wrong). 2. If using terminal to write code as well, open vi and type in the code. 3. Enter the following line of code at the command line while the terminal window is in the same folder as your .m and .h files:
clang -fobjc-arc -framework Foundation main.m -o yourAppName

This will compile the code into an executable file. To run, type
open yourAppName

at the command line. Alternatively, you can run your program by typing the program name preceded with ./ like so:
./yourAppName

Or you can add the name and path to your program to the PATH variable of your system.

Sunday, February 26, 2012

Objective-C: String to number to object conversion notes

So you need to add a double into an NSMutableArray, but you cannot do it directly because double is not an object. Here is how you wrap a double into an object type of NSNumber and add it to the array:
//create and initialize array:
NSMutableArray *arr = [NSMutableArray array];

//add your double to the array:
[arr addObject:[NSNumber numberWithDouble:yourNumber]];

//Here is how you unwrap it back into a double:
NSNumber *someNumber = [arr lastObject];

double d = [someNumber doubleValue];

Here is another handy trick, it turns out that NSString has a method that tries to return a double from the string itself. Here is how you write it:
NSString *myString = @"5.0";
double result = [myString doubleValue]; //I bet there is also a method to return an integer in the same manner

Here is how a double is converted to an NSString object:
NSString *resultString = [NSString stringWithFormat:@"%g", result];

Saturday, February 25, 2012

Objective-C, display object info using %@ format

If needed to display the object info in an informative manner using %@ format, implement the "description" method, like so:

-(NSString *) description
{
   return [NSString stringWithFormat: @"%i/%i/%i", _month, _day, _year];
}


The idea is the same as, for example, overriding ToString() method in C#.

Thursday, February 23, 2012

Create new object with some default parameters and NSMutable array to hold items


@interface Playlist : NSObject
@property (nonatomic, copy) NSString *playListName;
@property (nonatomic, strong) NSMutableArray *songs;

-(void)addSong:(Song *) aSong;
-(void)removeSong:(Song *)aSong;
-(id)initWithPlayListName:(NSString *)newPlayListName;
@end

//#import "Playlist.h"

@implementation Playlist
@synthesize playListName = _playListName, songs=_songs;

-(void)addSong:(Song *)aSong
{
    [_songs addObject:aSong];
}

-(void)removeSong:(Song *)aSong
{
    [_songs removeObject:aSong];
}

-(id)initWithPlayListName:(NSString *)newPlayListName
{
    self = [super init];
    if(self)
    {
        _playListName = newPlayListName;
        _songs = [NSMutableArray array];
    }
    
    return self;
}
@end

Objective-C tidbits

Sort an NSArray of NSIntegers:

NSArray *sorted = [arr sortedArrayUsingSelector:@selector(compare:)];


Iterate over items in NSCountedSet:

for(id i in set)
{
      NSLog(@"Item %@, count: %lu", i, (unsigned long)[set countForObject:i]);
}

Blog Archive