Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / XAML

Reminder - simple Windows Store App

4.82/5 (6 votes)
1 Apr 2014CPOL4 min read 17.1K   1.6K  
Reminder: simple Windows Store App. In this App I try to use some specific features for Windows 8 app. As result - i got good experience and now i want to show what was done.

Download ReminderWinForms-noexe.zip

Download ReminderWinForms.zip

Download Memo_01042014-noexe.zip

Download Memo_01042014.zip

Download Memo_no_NewtonPackage_noBin-noexe.zip

Introduction

Image 1

This app I try to realize as Windows Store App, so some new and specific things was used. List of interesting poinst:

  • DataConvertors
  • DataBindings
  • JSON usage
  • XAML
  • Layout for different device orientation (VisualStateManager)
  • Async methods
  • File usage (writing, reading)
  • Image usage
  • Toasts
  • BackgroundTasks
  • etc.

Background

I start to learn .Net a half year ago as a hobby, and first programm was Reminder in WinForms, now I try to do same things but in Windows Store App.

Basic idea for this app - create programm that allow in easy way add, edit, remove, search and remind different events. As was mentioned earlier, first version of my trying i create in WinForms (now i can see a lot of problems ther, errors, possibility for improvements and other thins - add to attachment varian in WinForms with name "eminderWinForms.zip").

Hope in nearest feature I'll look to this App and found possibility for improvement (some of them i know now - what need to do I place at the end of this Article).

Using the code and points of interest

So, lets look at the heart of my App.

I have few pages for different purposes :

  • MainPage
  • SearchPage
  • EditPage
  • AddEventPage

Also created CommonRuntimeComponent for BackgroundTask.

All pages I placed in same namespace - Memo, BackgroundTask - Tasks.

A lot of work was done in Xaml pages:

added few styles, created different Visual states. For me it's very interesting was to create VIsualStates using VisualStateManages. So I found 2 ways to do this:

  1. Create new VisualState and new layout - take a lot of time, but result - exactly what you need. Some times it can cause problem if you want to use controls in your c# code - due to different contols names.
  2. Modify properties of each Control - as result - much faster creating and no problem with Controls usage.
  3. Also you can combine this 2 methods.

Example (if you have few views of layout - just choose what exectly need to show)

XML
<!--Visual state manager-->
<VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
        <VisualState x:Name="defaultLayout">
        </VisualState>
        <VisualState x:Name="snappedLayout">
            <Storyboard>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="defaultView" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="portraitView" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="snappedView" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="narrowView" Storyboard.TargetProperty="Visibility">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>
        </VisualState>
   </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Also for correct working of this code you need to create refered c# code in your SizeChanged event of Page. Something like :

C#
private void pageRoot_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (e.NewSize.Width < 500 && (e.NewSize.Height > e.NewSize.Width) && e.NewSize.Width > 320)
    {
        VisualStateManager.GoToState(this, "narrowLayout", true);
    }
    else if (e.NewSize.Width > 500 && (e.NewSize.Height > e.NewSize.Width))
    {
        VisualStateManager.GoToState(this, "portraitLayout", true);
    }
    else if (e.NewSize.Width > 320)
    {
        VisualStateManager.GoToState(this, "defaultLayout", true);
    }
    else
    {
        VisualStateManager.GoToState(this, "snappedLayout", true);
    }
}

Same principle was used for all pages, as result - I got different layout for my app in different positions:

Image 2

Also very interesting for me was creating a DataConverter. I create few of them for different purpose - DateConverter, TimeConverter, PicturePathConverter, etc. Main principle - just implement IValueConverter. As sample - code for PicturePathConverter

C#
class PicturePathConverter: IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            string filePath = value.ToString(); //get path to picture
            BitmapImage image = new BitmapImage(); //create bitmap image blank

            if (filePath.Contains("Assets")) //if standart picture
            {
                Extensions.LoadImageFromAssetsLibrary(image, filePath);
                return image;
            }
            else
            {
                Extensions.LoadImageFromString(image, filePath);
                return image;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
     }
}

DataBinding - cool things that allow to show what you do even during designing stage. In additional using of this sometimes is very simple - just make few clicks, in other situation you need to do a liitle bit more. As sample of Binding - place part of code that allow to show my events from JSON file:

Xaml:

add namesapce for data usage

XML
xmlns:data="using:Memo.Data"

Create ViewSource and that use it in your layout

XML
<CollectionViewSource
           x:Name="itemsViewSource"
           Source="{Binding Events}"
           d:Source="{Binding Events, Source={d:DesignData Source=/DataModel/EventsData.json, Type=data:GroupOfEvents}}"/>

Result:

Image 3

New for me was JSON file - spend few days for reading about what it is and how i can use it, but after understanding and some trials - all come much more easy - just create object and use it. I store data in Json File. Sample of it:

VBScript
{"Events":
    [
      {
        "UniqueId": "Day-1-Item-1",
        "Name": "Event 1",
        "Place": "Item Subtitle: 1",
        "Description": "Event 1",
        "Start" : "2,25,2014,2,14",
        "End" : "2,25,2014,16,44",
        "ImagePath" : "Assets/appbar.calendar.png"
      },
      {
        "UniqueId": "Event 2",
        "Name": "Item Title: 1",
        "Place": "Item Subtitle: 1",
        "Description": "Event 2",
        "Start" : "2,25,2014,2,14",
        "End" : "2,25,2014,16,44",
        "ImagePath" : "Assets/appbar.calendar.png"
      }
    ]
}

For reading such file i Use next code:

C#
public static async Task<ObservableCollection<Event>> ReadFromJsonFileAsync(ObservableCollection<Event> events)
        {
            //create folder
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            //cehck existance of file
            if (await Extensions.CheckFileExistingByName(Extensions.fileToSaveEvents))
            {
                //create file
                StorageFile originalFile = await localFolder.GetFileAsync(Extensions.fileToSaveEvents);
                //read file
                using (IRandomAccessStream textStream = await originalFile.OpenReadAsync())
                {
                    // Read text stream     
                    using (DataReader textReader = new DataReader(textStream))
                    {
                        //get size                       
                        uint textLength = (uint)textStream.Size;
                        await textReader.LoadAsync(textLength);
                        // read it                    
                        string jsonContents = textReader.ReadString(textLength);
                        //create Json object for converting readed string
                        JsonObject jsonObject = JsonObject.Parse(jsonContents);
                        JsonArray jsonArray = jsonObject["Events"].GetArray();
                        //read each string
                        foreach (JsonValue jsonValue in jsonArray)
                        {
                            JsonObject eventObject = jsonValue.GetObject();
                            //add each event to groups with day
                            events.Add(new Event(eventObject["UniqueId"].GetString(),
                                eventObject["Name"].GetString(),
                                eventObject["Place"].GetString(),
                                eventObject["Description"].GetString(),
                                eventObject["Start"].GetString(),
                                eventObject["End"].GetString(),
                                eventObject["ImagePath"].GetString()
                                ));
                        }
                    }
                }
            }
            //return collection of exisisting events in file
            return events;
        }

A lot of time I spend for BackgroundTask - after reading MSDN article i think that it's easy - create Common Runtime Component and register task, but after some trial I found few limitation and so - spend some time for breaking it (if be hones - in this app still improvement for usage Background Task can be done). I try to understand how it's work and how it's can be used - result - every 15 min i check lst of events, and if it's exist - show toasts like :

Image 4

Also for implementing BackgroundTask you need to do next main things:

  • Create it in separate CRC
  • implement IBackgroundTask
  • class that implement IBackgroundTask must be sealed
  • if you use Async method - use deferal
  • create reference in your project for this component
  • register your task (add trigger - don't forget it). If you want to make timer - your app must realize Toast and notification, and must be placed on lockScreen
  • register your task in Package.appxmanifest
  • debug (just place stop point in RUN method of your class that implement IBackgroundTask)

Also some usefull samples and explanation can be found at MSDN. Like this one.

Think this is the most interesting points for me, that i currently investigate.

Points for improvement and known issues

Of couse ther is a lot of work that can be done more:

  • LifeCycle management
  • Share support
  • Implement IDisposable for my entity class (event)
  • Push notification
  • Settings
  • Spalsh screen
  • etc

Also i want to say few words about know issues:

  1. If you work with a big amount of events sometimes you can get Unhandled Win32 Exception
  2. BackgroundTask sometimes not fire (currently have no root cause for this)

History

This is the first published version of app.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)