C# Code, Tutorials and Full Visual Studio Projects

Jot the WPF Sticky Note App

Posted by on Jan 17, 2011 in Projects, WPF | 18 comments

Jot the WPF Sticky Note App

Jot is a sticky note taking application developed in C# using WPF.  Jot was created to help demonstrate that you can make a rich UI in WPF using MVVM.

This article will be looking at Jot and explain how it works so you can use some of the techniques in your own projects.

What is Jot?

Jot is a  sticky note application that lets you add notes to a canvas as well as headings. The notes and stamps (headings.) are dragable and allow the user to edit there contents. The canvas can be zoomed and panned and there is a search feature that hides notes that do not match your search criteria.

Watch the video and it will make more sense.

 

Grab a copy of the C# Code and follow along:

Download the Source Code

Model-View-ViewModel

A bit about the MVVM pattern for those not familiar with it. Think of it like MVC where your keeping your view and controlling logic separate.  In MVVM you create a ViewModel (like a controller class) that has all the logic. You also have a View that has the interface. The View is wired to the ViewModel via DataBinding so that changes in the ViewModel are reflected in the View.  The idea is to have almost no code in the code-behind files of your xaml windows.

Don’t worry this will make more sense by the time this is over.

Lets jump into the design…

Note Class

Jot has a Note class that holds the information for each note. (in MVVM it’s the model) A note has the following:

  • Body – this is the text the user types in.
  • Timestamp – each note keeps the time it was last modified. This is where that is saved.
  • Color – the background color of the note.
  • X – the location from the left edge of the container.
  • Y – the location from the top edge of the container.
  • Angle – each note has a slight random tilt. This is the angle of that tilt.

Since we need to notify other objects when our Note changes it needs to implement the PropertyChanged event, which is why such a simple class looks big.

using System;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace Jot.Models
{
    [Serializable]
    public class Note : INotifyPropertyChanged, IWidget
    {
        private int angle;
        private string body;
        private string color; //regular Color is not marked serializable so I use a hex string to represent color instead
        private DateTime timestamp;
        private double x;
        private double y;

        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        public DateTime Timestamp
        {
            get { return timestamp; }
            set
            {
                timestamp = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Timestamp"));
            }
        }

        public int Angle
        {
            get { return angle; }
            set
            {
                angle = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Angle"));
            }
        }

        public double Y
        {
            get { return y; }
            set
            {
                y = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Y"));
            }
        }

        public double X
        {
            get { return x; }
            set
            {
                x = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("X"));
            }
        }

        public string Color
        {
            get { return color; }
            set
            {
                color = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Color"));
            }
        }

        public string Body
        {
            get { return body; }
            set
            {
                body = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Body"));
                Timestamp = DateTime.Now;
            }
        }

        public bool IsMatch(string searchText)
        {
            return !string.IsNullOrEmpty(body) && Regex.IsMatch(body, searchText);
        }
    }

At some point we will need to save our notes so they don’t disappear each time the client is closed. This class will get serialized and saved to the disk, which is why there are attributes for serialization on a few things in there.

Also notice this implements an interface called IWidget? here is the code for that:

namespace Jot.Models
{
    public interface IWidget
    {
        bool IsMatch(string searchText);
    }
}

The interface ensures that both the Note and the Stamp (we’ll see that in a sec) have an IsMatch function. This function is used by the search to determine if a note matches the search text, basically each Note and Stamp is asked if they match the query being passed to the function, and it is up to the Note or stamp to give a true (match) or false (no match).

Stamp Class

After looking at the Note class none of the stuff in the stamp class should be new.

using System;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace Jot.Models
{
    [Serializable]
    public class Stamp : INotifyPropertyChanged, IWidget
    {
        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        private int angle;
        private double x;
        private double y;
        private string text;

        public string Text
        {
            get { return text; }
            set
            {
                text = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Text"));
            }
        }

        public int Angle
        {
            get { return angle; }
            set
            {
                angle = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Angle"));
            }
        }

        public double Y
        {
            get { return y; }
            set
            {
                y = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Y"));
            }
        }

        public double X
        {
            get { return x; }
            set
            {
                x = value;
                if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("X"));
            }
        }

        public bool IsMatch(string searchText)
        {
            return !string.IsNullOrEmpty(text) && Regex.IsMatch(text, searchText);
        }
    }

Pages: 1 2 3 4

18 Comments

Join the conversation and post a comment.

  1. Nathan Allen-Wagner

    Nice! This is a great little app. It looks nice and has quite a bit of functionality, yet the code is concise and easy to understand!

    I have an app that has to do some draggable / positioning stuff too. I like the approach you took with using the canvas as the hosting panel with item’s positions databound to the model / viewmodel.

    Nathan Allen-Wagner
    @nathanaw
    http://blog.alner.net/

  2. kelias

    Depending on what your looking for you could also use the WPF DragDrop Behavior. I haven’t posted anything on it yet but if you google it I’m sure you’ll find lots.

  3. John

    Thanks for the source code and explanations. It’s always nice to stumble upon fresh WPF content. The site looks awesome, btw.

  4. KEVIN

    THANK YOU!
    Awesome application,perfect post.

    just one think is not working: after using search function in this application, the NEW NOTE function is not working, while restarting the application.

    anyway thanks a lot, good job :)

  5. avastreg

    Hi

    Great job! Do you think it’s possible to run your code in Visual Studio 2008 instead of 2010? There are “drawback” problems?

    If is not compatible, can you explain or hint me about setup your code in 2008? How can i use the 2010 attatched dll?

    Thanks!

  6. kelias

    Sorry but I don’t have a good answer for that one. Been a long time since I played in 2008. As long your as using .NET 4 or at least 3.5, I would guess the majority of it should work fine.

  7. Andrew

    Wow, really awesome and useful application!
    Thank you very much.

    Sir I’m beginner in WPF, could you provide a detailed step by step tutorial how to do this application :)
    I think it’ll be very useful for everybody, Please share to us much detailed tutorial.

    Sincerely Andrew :)

  8. kelias

    It would probably be better to do some basic tutorials on WPF first. I’ll look at posting more content such as that, and then I can explain the techniques used here.

  9. Abdul Hassan

    nice tutorial on MVVM…. im going to use what i learnt to build a application which creates a table (panel or normal rectangle) and has a timer embedded into it, which shows on a label, time elapsed. just for practice. as practise makes perfect! Could i contact you to have a look at my code after i done it….

    Take care and carry on your generous knowledge share!!!

  10. M

    Thanks for your post on this. I’m just curious as to why you’ve chosen to use Dependency Object as the base class for the CorkboardViewModel?

  11. George P.

    I just downloaded the project but when i compile it i get an error.
    The reference AttachedCommandBehavior.dll was not found. It is not included in the project.
    Also reading the readme file i see that i must install a font but the path that points me to that font does not exist in the project. Please advice…

  12. admin

    The font is called “Birth Of a Hero.ttf” it’s in the project folder under one called Fonts. You can get AttachedCommandBehavior here

    Sorry about that I really should have added it to a lib folder in the zip file.

  13. George P.

    Thank you. It is working now.

  14. Pete

    Video is private??

  15. Kelly Elias

    YouTube had an issue and made all my videos private, not exactly sure why. But there public again now.

  16. Oleg Gazman

    Nice, Thanks for the source code and explanations.

  17. Ashto5

    I downloaded the source and it does not compile.

    Error

    Error 2 The tag ‘CommandBehaviorCollection.Behaviors’ does not exist in XML namespace ‘clr-namespace:AttachedCommandBehavior;assembly=AttachedCommandBehavior’. Line 21 Position 3. C:\Users\xxxx\Desktop\Jot\Jot\Views\CorkBoardView.xaml 21 3 Jot

  18. Kelly Elias

    You need to download AttachedCommandBehavior.

Leave a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>