সোজা সাপ্টা ম্যাশিন লার্নিং – কে নিয়ারেস্ট নেইবর (K Nearest Neighbour)

সত্যি কথা বলতে কি, আমরা সবাই একটা বেশ লম্বা থিসিস করে আসি চতুর্থ বর্ষে, আমি জানিনা অন্যদের কথা, কিন্তু অনেক কিছুই আমি ঠিকমতো বুঝিনাই, তাই ঠিকমতো বোঝার ইচ্ছা টা যায়নাই। সেই চেষ্টায় ভাবলাম, যেটুকু বুঝি , লিখে ফেলি। ম্যাশিন লার্নিং জিনিসটা ভারিক্কী শোনালেও জিনিস টার কাজ একটাই, একটা গবেট প্রকৃতির ম্যাশিন কে আপনি কোন নির্দিষ্ট ব্যাপারে ঠিক যে ভাবে চিন্তা করেন সেভাবে তাকে ভাবতে শিখানো বা অন্তত কাছাকাছি কিছু একটা চেষ্টা করা।

ম্যাশিন লার্নিং এ আমার মতো যারা নবিশ তাদের জন্য কিছু বলতে হলে বলা লাগে, যদি ম্যাশিন লার্নিং কে একটু ক্ল্যাসিফাই করার চেষ্টা করি তাহলে দুটো বড়সড় ভাগ পাবেন। প্রথমটার নাম সুপারভাইজড লার্নিং, আরেকটা আনসুপারভাইজড লার্নিং। কোনটা কি এগুলোর সংজ্ঞা নিয়ে ভটভট করার মতো জ্ঞান আমার নাই। তাই সোজা সহজ ভাবে বলি। যদি একটা ম্যাশিন কে শুরু থেকে কিছু শেখানো হয়, তারপর সে কিছু ঠিকঠাক মতো করতে পারে, সেটা দাঁড়ায় সুপারভাইজড লার্নিং এর দলে। বাকিটা হচ্ছে আনসুপারভাইজড।

ম্যাশিন লার্নিং থেকে ম্যাশিন শব্দ টা সরিয়ে ফেলুন, মনে করুন আপনি একটা ম্যাশিন। একটু সুবিধাজনক একটা পরিবেশ চিন্তা করতে গেলে আপনাকে একটু বোকা হতে হবে। ম্যাশিন সাধারণত বোকাসোকা হয়। তাহলে কি করা? চলুন ফেরত যাই ছোটবেলায়। একদম যখন ছোট ছিলেন আপনি তখন নিশ্চই আপনি এতো কিছু জানতেন না। তো সেই হিসাবে সেই সময়টায় আপনি এখনকার একটা বোকা ম্যাশিন এর মতোই ছিলেন। এখন বাকি থাকলো লার্নিং শব্দটা। সহজ কথায় শিক্ষা। আসুন ছোটবেলার আপনাকে কিছু শেখানো যাক।

ভয় নেই। বেশিদূর যাওয়া লাগবেনা। আপনার মার কথাই মনে করুন। আপনার মাই সম্ভবত আপনাকে শিখিয়েছেন সব কিছু্। চিন্তা করুন, আপনার মা আপনাকে চিনতে শিখিয়েছে কোনটা কি? ধরে নিলাম আপনার মা আপনাকে চিনিয়েছে আপেল, ধরে নিলাম, প্রথম আপেলটির রং ছিলো হালকা লাল। পরেরদিন আপনার মা আপনাকে দিলো একটি হালকা সবুজ রঙের আপেল, পরেরদিন একটু গাড় রঙের আরেকটি। চিন্তা করুন একবার, খুবই সাধারণ মনে হওয়া এই ঘটনাটি আসলে ম্যাশিন লার্নিং এর একটি অসাধারন উদাহরণ। আপনি (ম্যাশিন) প্রতিদিন দেখেছেন একটি ভিন্ন আপেল, ভিন্ন রং, ভিন্ন আকার এবং হতে পারে একটু ভিন্ন স্বাদের। কিন্তু আপনি জেনেছেন সব ই আপেল। যদি এমন হতো, প্রতিদিন এক ই রঙের, আকারের আপেল দেখতেন, আপনি হয়তো কোনদিন বিশ্বাস করতে পারতেন নাম আপেল অন্য আকার বা রঙের হয়। আপনার মা খুব নিভৃতে আপনাকে শিখিয়েছেন একটি সাধারণ আপেল দেখতে কেমন হয়। এটাকে সহজ কথায় Generalization বলে। যে কারণগুলো একটা আপেল থেকে বাকিগুলোকে আলাদা করেছে সেগুলোই Feature. একটু ভেবে দেখুন, যদি আমরা গোলকার আকৃতি এবং লাল রং কে আপেলকে অন্য সব কিছু থেকে আলাদা করার Feature হিসেবে ঘোষনা করি, তাহলে আপেলটা দিনশেষে কিছু লাল বলের সাথে গিয়ে জমা হতে পারে। এটিকে বলে Over generalization. আবার উল্টোটি হলে under generalization  ও হয়ে যেতে পারে। 🙂

সুতরাং বোঝাই যাচ্ছে ঘাপলাটা কোথায়। আপনাকে আপেল থেকে অন্য কিছু আলাদা করার জন্যে ঠিক সেই Feature গুলোই গ্রহণ করতে হবে যেগুলো over বা under generalization তৈরী করবেননা। এর মানে হচ্ছে গোলাকার আকৃতি Feature হিসেবে খুব একটা সুবিধার না, অনেক কিছুই গোলাকার হতে পারে। কিভাবে ভালো Feature বের করতে হয় সেটা নিয়ে আমরা ভটভট পরে করবো কোন এক দিন। আসেন কোন কিছু নিয়ে ভটভট করি। আমাদের আজকের লক্ষ্য K-Nearest Neighbor Algorithm দেখা, এটি আসলে একটি Classification Algorithm, সহজ কথায় যেগুলো দিয়ে অনেক কিছু থেকে জিনিসপত্র ভিন্ন ভিন্ন প্রকারে ভাগ করা হয়।

K-Nearest Neighbor Algorithm

K-Nearest Neighbour এর নাম ই যথেষ্ট আসলে এটি কি করে সেটা বোঝানোর জন্যে। সহজ বাংলায় এটি কোন কিছুকে ক্ল্যাসিফাই করে অনেকটা সে জিনিসটার আশেপাশের জিনিসগুলো কোন প্রকারের তার উপর থেকে। ধরুন আপনি একটি গোলাকার জিনিস অনেকগুলো আপেল আর বলের মধ্যে রাখলেন । কে নিয়ারেস্ট নেইবর যেটা বলে সেটা হচ্ছে  আপনার রাখা নতুন বস্তুটি আশেপাশের অধিকাংশ বস্তু যে প্রকারের সেই প্রকারের মধ্যে পরে। যদি আশেপাশের অধিকাংশ জিনিস বল হয়, তাহলে সেটি বল অথবা সেটি আপেল। আজগুবি ঠেকলেও ভুলে যাবেন না, আপনি কিন্তু যে কোন জায়গায় আপনার অজানা জিনিসটি বসাতে পারবেন না। বসাবেন আসলে তার ফিচারের ভিত্তিতে। যদি সেটি সত্যি আপেল হয় এবং আপনার ফিচার ঠিকমতো নির্ণয় করা হয়ে থাকে তাহলে সেটি অবস্থান নেবে আপেলদের পাশেই। তার মানে এই নাম এই অ্যালগরিদম একেবারেই ভুল করেনা। তবে সেটা নিয়ে পরে কথা বলি না হয়।

ছোট্ট একটি উদাহরণ:

মনে করুন, আপনার কাছে এইরকম একটি ডাটাসেট আছে।

Rooms Area Type
1 350 apartment
2 300 apartment
3 300 apartment
4 250 apartment
4 500 apartment
4 400 apartment
5 450 apartment
7 850 house
7 900 house
7 1200 house
8 1500 house
9 1300 house
8 1240 house
10 1700 house
9 1000 house
1 800 flat
3 900 flat
2 700 flat
1 900 flat
2 1150 flat
1 1000 flat
2 1200 flat
1 1300 flat

দেখেই বোঝা যাচ্ছে এটি আকার এবং রুম সংখ্যার ভিত্তিতে আপনার বাসাটি অ্যাপার্টমেন্ট, ফ্ল্যাট না হাউজ সেটার প্রকারভেদ। তাহলে এখানে সহজ কথায় রুম সংখ্যা এবং আকার আমাদের ফিচার। এই স্যাম্পল সেটটি যদি আমরা কোন ম্যাশিন কে শিখাই, তাহলে এটার উপর ভিত্তি করে সে নতুন কোন নোড এই কোন ক্যাটাগরিতে পরে সেটা আপনাকে জানিয়ে দেবে। প্রশ্ন হচ্ছে কিভাবে। আমরা যেটা করবো এখন সেটি হচ্ছে একটি দ্বিমাত্রিক কার্তেসীয় স্থানাংক ব্যবস্হায় X অক্ষ বরাবর Room সংখ্যা এবং Y অক্ষ বরাবর বসাবো Area. এখন এই ছকে নতুন কোন বাসা যখন আসবে তখন সেটিও হবে আসলে একটি ডাটা পয়েন্ট মাত্র। আমরা সেটির আশে পাশের K সংখ্যক ডাটা পয়েন্ট গুলো থেকে দেখে নিবো সেটি কোন প্রকারে পরে। সহজ বাংলায় আমাদের অ্যালগরিদম টা দাঁড়ায় এরকম :

১. স্যাম্পল ডাটা সহ যে সকল Mystery Point (যেগুলো কোন প্রকারে পরে আমরা জানিনা)  বসিয়ে দিন ছকে
২. বের করে নিন Mystery Point গুলো থেকে সকল পয়েন্ট এর দূরত্ব। ৩. এরপর বেছে নিন কাছের K সংখ্যক প্রতিবেশী পয়েন্ট কে।
৪. k সংখ্যক প্রতিবেশীদের সর্বোচ্চ সংখ্যক প্রতিবেশী যে প্রকারের আপনার Mystery Point ও সেই প্রকারের।

আসুন আমরা ছোট্ট একটা কোডে চলে যাই।

কোড:

আমি কোড করার প্ল্যাটফরম হিসেবে নিয়েছি উইন্ডোজ ফোন ৮ এবং আমি চার্ট এর জন্যে ব্যবহার করছি আমার পছন্দের Telerik Rad Controls. আপনারা চাইলে স্প্যারো টুলকিট ব্যবহার করতে পারেন। এটি ফ্রি এবং চমৎকার। চাইলে যে কোন ল্যাংগুয়েজে কোড করে ফেলতে পারেন। আমি এখানে অসম্ভব crude code করে গেছি এবং চেষ্টা করে গেছি কোড বড় হলেও বোধগম্য রাখার। আপনি আপনার মতো সাজিয়ে নেবেন। 🙂

আমরা প্রথমে Node  এবং NodeList নামের দুটি ক্লাস নিয়ে কাজ করবো।

class Node শুরুতে দেখতে অনেকটাই এরকম:

public class Node
{
public int Rooms { get; set; }
public int Area { get; set; }
private NodeType _type = NodeType.unknown;
public NodeType Type {
get
{ return _type; }
set
{
_type = value;
SetForeground();

}
}

private void SetForeground()
{
if (_type == NodeType.apartment)
{
Foreground = new SolidColorBrush(Colors.Red);
}
else if (_type == NodeType.flat)
{
Foreground = new SolidColorBrush(Colors.Green);
}
else if (_type == NodeType.house)
{
Foreground = new SolidColorBrush(Colors.Blue);
}
else
{
Foreground = new SolidColorBrush(Colors.White);
}
}

public SolidColorBrush Foreground { get; set; }

public ObservableCollection Neighbours { get; set; }

public double Distance { get; set; }

public Node()
{

}

}

এখানে প্রথমে যেটা চোখে পরে, সেটা হচ্ছে শুরুতেই Rooms এবং Area বলে দেয়া শুরুতে। এই দুটো আমাদের ফিচার, একটি Node একটি বাসাকে প্রকাশ করে এখানে। সুতরাং এগুলো শুরুতেই ডিফাইন করা। এরপর দেখা যাচ্ছে NodeType বলে দেয়া এবং NodeType এর ভিত্তিতে একটি Foreground বলে দেয়া। এটি করা হয়েছে শুরু চার্ট তৈরী করার সুবিধার্থে। আসুন দেখে নেই NodeType enum টি কিরকম।

public enum NodeType
{
[Description("apartment")]
apartment,
[Description("house")]
house,
[Description("flat")]
flat,
[Description("unknown")]
unknown
}

স্পষ্টতই দেখা যচ্ছে টাইপ গুলো আমরা আমাদের স্যাম্পল ডাটার মতো বলে নিয়েছি। শুধু unknown টাইপটি আমাদের Mystery Point এর জন্যে। যাতে আমরা চার্টে আলাদা করতে পারি কোনটার টাইপ আমি জানিনা। এবার আসুন NodeList ক্লাসটি কিরকম দেখে নেই

public class NodeList
    {
        private int MinAreas { get; set; }
        private int MinRooms { get; set; }

        private int MaxAreas { get; set; }

        private int MaxRooms { get; set; }

        public ObservableCollection<Node> Nodes { get; set; }
        public int K { get; set; }

        public NodeList()
        {
            MinAreas = MinRooms = 100000;
            MaxAreas = MaxRooms = 0;
        }

    }

এখানে দেখা যাচ্ছে MinAreas, MaxAreas এবং MinRooms, MaxRooms নামের কয়েকটি প্রোপার্টি ডিফাইন করা। এগুলো আরো সহজেই করা যায়। কিন্তু কাজের এবং বোঝার সুবিধার্থে আলাদা করে লেখা। যে দুটি প্রোপার্টি জরুরী তা হচ্ছে Nodes এবং K . Nodes হচ্ছে আপনার ম্যাশিনের শেখা সমগ্র নোড গুলো (উপরের বাসার লিস্ট) এবং K হচ্ছে কতজন প্রতিবেশী নোড কে আমরা বিবেচনায় আনবো সেটির সংখ্যা। আপনি চাইলে Nodes কালেকশনটি কনস্ট্রাকটর ডিপেন্ডেন্সি তে ঢুকিয়ে দিতে পারেন। কিন্তু আমি আগেই বলেছি, এই পুরো লেখার উদ্দেশ্য বোঝানো, তাই কোডের এই দুরবস্থা। 😛
আসুন আর একটু আগানো যাক। এখন আমাদের Mystery Point থেকে সকল পয়েন্ট এর দূরত্ব বের করার কথা। কিন্তু তার আগে কিছু কথা বলা প্রয়োজন।

নরমালাইজেশন

একটু ভালো করে দেখুন, আমাদের দেয়া স্যাম্পল ডাটাতে রুম সংখ্যা ১ থেকে ১০ এর মধ্যে এবং রুম সাইজ ২৫০ তে ১৭০০ এর মধ্যে। তার মানে আমাদের x অক্ষ বরাবর বিন্দুগুলোর দূরত্ব Y অক্ষ বরাবর বিন্দুগুলোর দূরত্ব হতে গড়ে কম হবে। এটিতে যেটা হতে পারে, একটি বাসা ছকে তার সর্ব্বোচ্চ কাছাকাছি বিন্দু হতে অপেক্ষাকৃত দূরে সরে যেতে পারে এবং ভুল বিন্দুর কাছে X অক্ষ বরাবর কাছে চলে আসতে পারে। ফলে আপনার অ্যালগরিদম এর ফলাফল ক্ষতিগ্রস্ত হতে পারে। আসুন সব ভ্যালু গুলোকে আমরা ০ হতে ১ এর মধ্যে নিয়ে আসি। সহজ বাংলায় আমরা আমাদের গ্রাফটিকে বর্গাকার করে নিচ্ছি যাতে X অক্ষ এবং Y অক্ষ এর গুরুত্ব সমান থাকে। আপনি যদি চান আপনার ক্ল্যাসিফিকেশনে রুম সংখ্যা বেশি গুরুত্ব পাবে। তাহলে আপনি যেকোন অক্ষের দুরত্ব কমিয়ে আনতে পারেন। একে Weighting বলে। সেটা না হয় পরে।

দুই অক্ষের সকল ভ্যালু ০ হতে ১ এর মধ্যে আনতে হলে দুই অক্ষের সর্ব্বোচ্চ এবং সর্বনিম্ন মান আমাদের জানতে হবে এবং সেটাকে অক্ষভেদে মানের পার্থক্য দিয়ে ভাগ দিতে হবে। আসুন কোড দেখে বুঝে নেই:

        private void CalculateRanges()
        {
            if(Nodes!=null && Nodes.Count>0)
            {

                foreach (var node in Nodes)
                {
                    if (node.Rooms < MinRooms)
                        MinRooms = node.Rooms;
                    if (node.Rooms > MaxRooms)
                        MaxRooms = node.Rooms;

                    if (node.Area < MinAreas)
                        MinAreas = node.Area;
                    if (node.Area > MaxAreas)
                        MaxAreas = node.Area;
                }
            }
        }

CalculateRanges() মেথডটি NodeList ক্লাসে যোগ করা। দেখেই বোঝা যাচ্ছে খুবই আনাড়ি কোড কিন্তু বোঝার জন্যে এটি অসাধারণ। খেয়াল করে দেখুন CalculateRanges() শুধুমাত্র room এবং area (আমাদের x এবং y অক্ষ) এর সর্ব্বোচ্চ এবং সর্বনিম্ন মান খুঁজে বের করছে। আর কিছু নয়। এখন যেহেতু আমাদের হাতে দুই অক্ষের সর্ব্বোচ্চ এবং সর্বিনম্ন মান আছে সেহেতু আমরা মূল অ্যালগরিদমে প্রবেশ করতে পারি।

public void DetermineUnknown()
        {
            //start the calculation of range;
            this.CalculateRanges();

            foreach (var node in Nodes)
            {
                if(node.Type == NodeType.unknown)
                {
                    node.Neighbours = new ObservableCollection<Node>();
                    foreach (var NNode in Nodes)
                    {
                        if (NNode.Type == NodeType.unknown)
                            continue;
                        node.Neighbours.Add(NNode);

                    }

                    //Measure Distance Now

                    node.MeasureDistances(MaxRooms - MinRooms, MaxAreas - MinAreas);

                    //Sort it out
                    node.Neighbours = new ObservableCollection<Node>(node.Neighbours.OrderBy(x => x.Distance).ToList());

                    //Guess the type
                    node.GuessType(this.K);
                }
            }
        }

এক বস্তা জিনিস এক সাথে লিখে ফেললাম, এই তো? আসুন আস্তে আস্তে আগাই। আমরা CalculateRanges() আগেই দেখেছি। শুরুতেই লুপে ঘুরছে আমাদের সব স্যাম্পল ডাটা (যেখানে আমাদের Classification না জানা Mystery Points গুলো, মানে যে বাসাগুলো কোন প্রকারের আমরা জানিনা সেগুলোও আছে এবং অবশ্যই স্যাম্পল ডাটা সেট ও আছে)। দেখা হয়েছে NodeType unknown কিনা, হলে সেটিই সেই বাসা যেটির প্রকার আমরা জানিনা, তার মানে সেটি Mystery Point গুলোর একটি। আসুন সেটিকে classify এর ব্যবস্থা করি। শুরুতে ই লাগবে সকল প্রতিবেশী সকল নোড হতে দূরত্ব্। না হলে কাছের গুলো বের করবেন কিভাবে। সেজন্যে MeasureDistances() ব্যবহার করা। দেখে আসি মেথডটি দেখতে কেমন হতে পারে। খেয়াল করে দেখুন, আরগুমেন্ট দুটি হচ্ছে Rooms এবং Areas এর মানের পার্থক্য। এটি আমাদের Normalize করতে সাহায্য করবে।

        internal void MeasureDistances(int RoomRange, int AreaRange)
        {
            foreach (var neighbour in Neighbours)
            {
                double delta_rooms = neighbour.Rooms - this.Rooms;
                delta_rooms = delta_rooms / (double)RoomRange;

                double delta_area = neighbour.Area - this.Area;
                delta_area = delta_area / (double)AreaRange;

                neighbour.Distance = Math.Sqrt(delta_rooms * delta_rooms + delta_area * delta_area);

            }
        }

এখানে দূরত্ব বের করার আগে Normalization করো হয়েছে। তার মানে আমরা প্রতিটি প্রতিবেশীর Room এবং Area এর মানের পার্থক্য কে Room এবং Area এর সর্বোচ্চ এবং সর্বনিম্ন মানের পার্থক্য দিয়ে ভাগ দিয়ে এই মানগুলোকে ০ হতে ১ এর মধ্যে নিয়ে আসছি। এর পর আমরা পিথাগোরাসীয় দূরত্ব বের করছি। একটি জিনিস লক্ষ্য করে দেখুন। আমাদের ফিচার সংখ্যা দুইটি হওয়ায় আমরা দ্বিমাত্রিক কার্তেসীয় স্থানাংক ব্যবস্থায় আমরা বিন্দুগুলোকে X অক্ষ এবং Y অক্ষে আলাদা করে লিখেছি। এইজন্য দ্বিমাত্রিক দুটি বিন্দুর দূরত্ব বের করার সূত্র হচ্ছে Math.Sqrt(x * x + y * y)
যদি আপনার ফিচার তিনটি হতো তাহলে ছকটি ত্রিমাত্রিক স্থানাংক ব্যবস্থায় চলে আসতো। তখন দুই বিন্দুর দূরত্ব হতো Math.Sqrt(x * x + y * y+ z*z)
এইভাবে n সংখ্যক ফিচারের জন্য n মাত্রিক স্থানাংক ব্যবস্থায় দুই বিন্দুর দূরত্ব হতো Math.Sqrt(x * x + y * y+ z*z+ …..+ n*n)
আপনি চাইলে একটি n মাত্রিক স্থানাংক ব্যবস্থাকে কমিয়ে এনে দ্বিমাত্রিক ব্যবস্থায় প্রোজেক্ট করতে পারেন। তবে সেগুলো অন্য কোন দিন। যেটা আমি এখানে বোঝাতে চেয়েছিলাম সেটি হচ্ছে এটিই KNN এর ক্ষমতার পরিচায়ক, আপনার ফিচার সংখ্যা যাই হোক না কেন, সেটি আরামসে কাজ করতে পারে। তবে মনে রাখবেন বেশি ফিচার মানেই ভালো ক্ল্যাসিফিকেশন তা নয়। তাতে সেই generalization সংক্রান্ত জটিলতায় পড়তে পারেন।

তো MeasureDistances() এর পরে আমাদের কাজ হচ্ছে দূরত্বের ভিত্তিতে প্রতিটি নোডের প্রতিবেশীর লিস্ট কে সর্ট করা। কারণ আমরা k সংখ্যক কাছের প্রতিবেশী নিয়ে আগ্রহী। এর পরেই চলে আসে Mystery Point টি যেটির প্রকার আমরা জানিনা (যে বাসাটি ফ্ল্যাট, অ্যাপার্টমেন্ট না হাউজ আমরা জানিনা) সেটির প্রকার খুঁজে বের করা। সেই কাজটি করে GuessType()

internal void GuessType(int k)
        {
            int[] TypeVotes = new int[4]; //There are three types;

            var EligibleNeighbours = this.Neighbours.Take(k).ToList();

            foreach(var eligibleNode in EligibleNeighbours)
            {
                TypeVotes[(int)eligibleNode.Type] ++;

            }

            NodeType GuessedType = (NodeType)TypeVotes.Max();

            MessageBox.Show("Guessed type for node is " + GuessedType.ToString());

            this.Type = GuessedType;
        }

আমরা চলে এসেছি প্রায় শেষে, দেখুন এটি কোন নোডের প্রতিবেশী হতে খুঁজে বের করে সর্বোচ্চ কাছের k সংখ্যক প্রতিবেশী কে । এবং এদের থেকে সর্বোচ্চ সংখ্যক প্রতিবেশী যে প্রকারের আপনার Mystery Point টি ও সেই প্রকারের বলে ঘোষনা করে। মানে এখানেই আপনি জেনে যাবেন আপনার বাসাটি কোন প্রকারের।

উইন্ডোজ ফোনে উদাহরণ:

‌উইন্ডোজ ফোনে আমি একটি ছোট্ট MVVM অ্যাপ বানিয়ে পরীক্ষা করেছি অ্যালগরিদম টি। পুরো কোড শেষে দেয়া আছে। তাই MainviewModel এর কিছু অংশ আমি তুলে দিচ্ছি:

        public MainViewModel()
        {

            TestKnnCommand = new RelayCommand(TestKnnAction);
            LoadSamples();
            AddASample();
        }

        private void TestKnnAction()
        {
            NodeCollection.DetermineUnknown();
        }

        private void LoadSamples()
        {

            using(StreamReader reader= new StreamReader("SampleData.txt"))
            {
                var data = reader.ReadToEnd();
                List<Node> datArray = JsonConvert.DeserializeObject<List<Node>>(data, new StringToEnumConverter());
                var _sampleCollection = new ObservableCollection<Node>(datArray);

                NodeCollection = new NodeList();
                NodeCollection.K = 3;
                NodeCollection.Nodes = _sampleCollection;

            }

        }

        private void AddASample()
        {
            Node newNode = new Node() { Area = 500, Rooms = 2, Type = NodeType.unknown };
            NodeCollection.Nodes.Add(newNode);
        }

আমি শুধু শুরুতে লোড করে নিয়েছি আমার স্যাম্পল ডাটা গুলো। এরপর যোগ করে নিয়েছি একটি অজানা Mystery Point , মানে এমন একটি বাসা যেটি কোন প্রকারের আমি জানিনা। K এখানে ৩, তার অর্থ হচ্ছে আমি ৩ টি কাছের প্রতিবেশী ব্যবহার করবো classification এর জন্যে।
TestKnnAction() একটি action যেটি একটি বাটন হতে command এর সাহায্যে invoke করা হয়। এবং এটি অজানা পয়েন্ট টির ক্ল্যাসিফিকেশন বের করার জন্য DetermineUnknown() ব্যবহার করে। আপনি চাইলে একাধিক স্যাম্পল যোগ করে অ্যালগরিদম টি চালিয়ে দেখতে পারেন।

জেনে রাখা ভালো:

অন্য সকল ক্লাসিফিকেশন অ্যালগরিদম এর মতোই এটিতেও সমস্যা আছে। আপনার ডাটা সেট যদি পৃথক করার যোগ্য (Separable) হয় তবেই এটি বেশ ভালো কাজ করে। আর যদি তা না হয় আপনি এমন একটি ছক পাবেন যেটায় বিন্দু গুলো সব জায়গায় ছড়িয়ে আছে এবং ফলশ্রুতিতে আপনি ভালো ফলাফল পাবেন না। বরং আপনি যদি ছকে দেখেন বিন্দুগুলো cluster বা গুচ্ছে গুচ্ছে বিভক্ত তাহলে বুঝবেন এটি Separable বা পৃথক করার যোগ্য। আরেকটি জিনিস, নোডসংখ্যা বাড়লে আপনার ক্যালকুলেশন টাইম ও বাড়বে। তাই আপনি চাইলে Pruning করতে পারেন। যেমন যে বাসার Room সংখ্যা ২ তার জন্যে যে সকল বাসা যাদের room সংখ্যা ৬ এর অধিক তাদের সাথে দূরত্ব বের করা অর্থহীন।

আশা করি সবার ভালো লাগবে। অ্যাপ এর দুটি স্ক্রিনশট তুলে দিলাম।

Initial KNN Graph

classification result

কোডটুকু পাওয়া যাবে এখানে। যদিও আপনার Telerik Rad Controls for Windows Phone 8 এর লাইসেন্স থাকা লাগবে এটি বিল্ড করার জন্যে। তবুও দিয়ে দিলাম : http://1drv.ms/1DOTVu8

বাংলায় উইন্ডোজ ফোন — Introduction to MVMMLight

আবার ফিরে এলাম অনেকদিন পর। আজকের ভিডিওটি mvvmlight toolkit এর ওপর। mvvmlight অসম্ভব জনপ্রিয় একটি mvvm toolkit. আসুন দেখে নেই mvvm এর বেসিক কিছু কাজ কিভাবে এটি দিয়ে খুব সহজেই করে নেয়া যায়।

বাংলায় উইন্ডোজ ফোন – DelegateCommand, The Reusable ICommand

অনেকদিন পর ফেরত আসলাম। আজকের টিউটোরিয়াল ICommand এর একটি সহজ ও Reusable Implementation যার নাম DelegateCommand, তার উপরে। DelegateCommand implement হয় ICommand interface দিয়েই এবং এটি ICommand এর ব্যবহারকে অনেকটাই সহজ করে দেয়। আশা করি সবার ভালো লাগবে।

পুনশ্চ: যদি আপনি Introduction to ICommand দেখে না থাকেন তাহলে অনুগ্রহ করে দেখে আসুন।

 

প্রজেক্ট সোর্স পাওয়া যাবে এই লিংকে – http://sdrv.ms/1dYX3pT

Binding Command to custom Pushpin in Windows Phone 8 Map Control

Well, this one’s kind of out of line. I faced this last night, searched all over I can but I barely found a concise solution on this one.

Before we get into the solution, we need to see the problem we’re talking about. Shouldn’t we?

I was working with the new Windows Phone 8 Map Control provided with the sdk that allows here maps to be used in your app and I needed a bunch of Pushpins to be loaded in the map. So, Windows Phone Toolkit came to the rescue. I hooked up the <MapExtensions.Children> and added by pushpins there binded from my viewmodel.

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" >

            <maps:Map x:Name="MyMap" ZoomLevelChanged="MyMap_ZoomLevelChanged"  Loaded="MyMap_Loaded"   >

                <MapToolkit:MapExtensions.Children>

                    <MapToolkit:MapItemsControl Name="MapElements">
                        <MapToolkit:MapItemsControl.ItemTemplate>
                            <DataTemplate>
                                <MapToolkit:Pushpin Name="StopPushPin"  Style="{StaticResource MaximizedPushpin}"  Background="#B20000FF" Content="{Binding Name}" GeoCoordinate="{Binding Location}" Tap="Pushpin_Tap"  >
                                </MapToolkit:Pushpin>
                            </DataTemplate>
                        </MapToolkit:MapItemsControl.ItemTemplate>
                    </MapToolkit:MapItemsControl>
                    <MapToolkit:Pushpin Name="MyPushpin"  Content="I'm Here!" Background="#FF3CD303"  GeoCoordinate="{Binding MyLocation}" />
                </MapToolkit:MapExtensions.Children>

            </maps:Map>
        </Grid>

One could easily see here that I used a PushPin object as DataTemplate with a custom style attached. Lets check the style

<Style TargetType="MapToolkit:Pushpin" x:Key="MaximizedPushpin">

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="MapToolkit:Pushpin">
                    <Grid x:Name="ContentGrid" FlowDirection="LeftToRight">

                        <toolkit:WrapPanel Orientation="Vertical">

                            <Grid x:Name="grid" Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}" HorizontalAlignment="Left"
                                   RenderTransformOrigin="0.5,0.5" Height="148" Width="225">

                                <Grid.RowDefinitions>
                                    <RowDefinition Height="0.4*"></RowDefinition>
                                    <RowDefinition Height="0.015*"></RowDefinition>
                                    <RowDefinition Height="0.25*"></RowDefinition>
                                    <RowDefinition Height="0.015*"></RowDefinition>
                                </Grid.RowDefinitions>

                                <TextBlock Margin="8,4,4,4"
                                           FlowDirection="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=FlowDirection}"
                                           Grid.Row="0" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"
                                           TextWrapping="Wrap" FontSize="30">

                                </TextBlock>

                                <Border Grid.Row="1" Background="#CC474444" Margin="0,0,-6,0" />
                                <Grid Grid.Row="2"   MinHeight="31" Background="#EEF9F9F9" Margin="0,0,-8,0"  >
                                    <codefun:RoundButton Orientation="Horizontal" Foreground="Black" Background="Transparent"
                                                         BorderBrush="Black" ImageSource="/Assets/pushpin.get.direction.png"
                                                         HorizontalAlignment="Left" VerticalAlignment="Center"
                                                         Margin="0,2,0,0"
                                                         >
                                    </codefun:RoundButton>
                                </Grid>
                                <Grid Grid.Row="3"   Background="#99474444" Margin="0,0,-6,0"/>
                            </Grid>

                            <Polygon Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}"
                                     Points="0,0 29,0 0,29"
                                     Width="29"
                                     Height="29"
                                     HorizontalAlignment="Left"/>
                        </toolkit:WrapPanel>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="PositionOrigin" Value="0,1" />
        <Setter Property="Background" Value="Black" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="FontSize" Value="30" />
    </Style>

All I wanted to do is to bind Command Parameter of RoundButton and hook a RelayCommand in my viewmodel. As is an attached property in the Map control I had to use FindAncestor mode when I tried to bind Command parameter in RoundButton. But bad news is it’s not supported in Windows Phone. The only relative binding mode I have here is templatedparent and self.

And I started looking for a solution. Then this came to my eyes and I was really happy. So, I followed as per what was written in there and voila!

I binded the Command with CommandParameters the following way.

<codefun:RoundButton Orientation="Horizontal" Foreground="Black" Background="Transparent"
                                                         BorderBrush="Black" ImageSource="/Assets/pushpin.get.direction.png"
                                                         HorizontalAlignment="Left" VerticalAlignment="Center"
                                                         Margin="0,2,0,0"
                                                         CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}"
                                                         >

                                        <BindHelper:BindingHelper.Binding>
                                            <BindHelper:RelativeSourceBinding
                                                Path="GetDirectionToPushPinCommand"
                                                TargetProperty="Command"
                                                RelativeMode="ParentDataContext"
                                                />

                                        </BindHelper:BindingHelper.Binding>
                                    </codefun:RoundButton>

A handy tool indeed!

বাংলায় উইন্ডোজ ফোন – Introduction to ICommand

ফিরে আসলাম আবার। আজকের টিউটোরিয়াল ICommand এর উপরে। নিঃসন্দেহে  অত্যন্ত গুরুত্বপূর্ন একটি interface যেটা MVVM approach এ বড় ভূমিকা পালন করে। আশা করি সবার ভালো লাগবে। 🙂

স্যাম্পল প্রজেক্ট ডাউনলোড করে নিন নিচের লিঙ্ক থেকে :
http://sdrv.ms/1eouqSL

Data Binding – The last words

Well, as the title says this would be my last points on Data Binding. That doesn’t actually mean this is all there is in data binding. Kindly consider I only could share two or three lines from the preface of the book named “Data Binding”. But as we need to move forward I’m only sharing what’s essential to know.

So, back with the same example we had in our last post. If we remember things correctly we left the work at this stage:

wp_ss_20130929_0001

If we remember correctly we used the button Update Data to update the data from C# code behind. What if we want to write something in the textboxes and want to update the data by clicking the button Update Data. Only this time the new Data would be what I write in the textboxes.

So, lets see what we did before first approach that might come to your head is to write something like this:

 private void Button_Click(object sender, RoutedEventArgs e)
        {
            _personModel.Name =Name.Text;
            _personModel.Age = Age.Text;
            _personModel.Height = Height.Text;
        }

Well, I don’t blame you. It’s fair to do so. But if we don’t want the button, we just want to type and it will update automatically? Well, I know, who wants that ? :\

But what if it’s a data field and we have next button to go to another field like we do have in installation wizards, we don’t need a update button in that case. So, lets rename the Update button to Read Data so we can check that the data is updated truly.  So, lets change the button name and change the “Button_Click” event as following:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Name.Text = _personModel.Name;
            Age.Text = _personModel.Age;
            Height.Text = _personModel.Height;
        }

So, now it would read the data instead of writing it. Then who is going to write it! :\
Well, lets change the data binding mode to TwoWay and we’re done for the updating!


<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
   <TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="Name" Text="{Binding Name, Mode=TwoWay}" VerticalAlignment="Top" Width="450" />
   <TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="Age" Text="{Binding Age, Mode=TwoWay}" VerticalAlignment="Top" Width="450" />
   <TextBox Height="72" HorizontalAlignment="Left" Margin="0,284,0,0" Name="Height" Text="{Binding Height, Mode=TwoWay}" VerticalAlignment="Top" Width="450" />
   <Button Content="Read Data" Click="Button_Click" Margin="0,361,0,159" ></Button>
</Grid>

You see what I did here is, I changed the Text Property of the Name TextBox control to Text=”{Binding Name, Mode=TwoWay}” and I changed all the TextBoxes accordingly allowing it to update the underlying data automatically when it’s changed. 🙂 No need for an update button.

DON’T USE IT IF YOU DON’T WANT TO CHANGE THE UNDERLYING DATA WITHOUT ANY CONFIRMATION.

So, you see the amazing thing here is all I changed is the binding mode. If I didn’t have to read this using the button we wouldn’t have needed any code practically.

Now Let’s get to see Element Binding a bit

Well, to demonstrate element binding what are we going to do is, we’re gonna put a slider control in our ContentPanel. Whenever we change the value of the slider we want to see that in a TextBlock. So we will get rid of all the textboxes and we will  insert a slider in our Windows Phone project.

Slider and Textblock

So, you see, we added a TextBlock and a slider below and removed the button and textboxes that were here before.

So, our ContentPanel looks like this now.

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock Height="70"
                     HorizontalAlignment="Left"
                     Margin="10,130,0,0"
                     Name="ValueBox"
                     Text="TextBlock"
                     FontSize="36"
                     VerticalAlignment="Top"
                     TextAlignment="Center"
                     Width="436" />
            <Slider x:Name="HSlider" Orientation="Horizontal"
                    HorizontalAlignment="Left"
                    Height="172"
                    Margin="10,200,0,0"
                    VerticalAlignment="Top"
                    Width="436"
                    LargeChange="10"
                    SmallChange="1"
                    Minimum="0"
                    Maximum="100"
                    Value="50"

                    />
        </Grid>

Lets look at the xaml for a minute. You will see the slider named HSlider has a horizontal orientation and Minimum and Maximum value set from 0 to 100. What we want is we want to see the slider value on the textblock above, it should change as we change the slider. What’s the first approach comes to your mind. We can set a ValuChanged event in the slider and show the value in the textblock like this.

Adding a ValueChanged event in the XAML:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock Height="70"
                     HorizontalAlignment="Left"
                     Margin="10,130,0,0"
                     Name="ValueBox"
                     Text="TextBlock"
                     FontSize="36"
                     VerticalAlignment="Top"
                     TextAlignment="Center"
                     Width="436" />
            <Slider x:Name="HSlider" Orientation="Horizontal"
                    HorizontalAlignment="Left"
                    Height="172"
                    Margin="10,200,0,0"
                    VerticalAlignment="Top"
                    Width="436"
                    LargeChange="10"
                    SmallChange="1"
                    Minimum="0"
                    Maximum="100"
                    Value="50"
                    ValueChanged="HSlider_ValueChanged_1"
                    />
        </Grid>

and write the event handler behind in MainPage.xaml.cs like this:

private void HSlider_ValueChanged_1(object sender, RoutedPropertyChangedEventArgs e)
        {
            if(HSlider!=null)
                this.ValueBox.Text = HSlider.Value.ToString();
        }

And if you build this and run it on the emulator or device, whenever you change the slider you will see it’s value in the textblock. But is that we wanted here? NOOOO!!

Let’s make things a bit simple. If we can bind the slider to textblock item we can instantly show the slider value on the textblock. No code needed whatsoever! And why we bind the slider to the textblock. Because here the textblock shows the data so the slider works here as the model and the textblock as view! So, the model is binded to the view!

Let’s chill and see the easiest trick here. Now our ContentPanel looks like this and we have got rid of the event handler named HSlider_ValueChanged_1 from MainPage.xaml.cs

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock Height="70"
                     HorizontalAlignment="Left"
                     Margin="10,130,0,0"
                     Name="ValueBox"
                     Text="{Binding Value, ElementName=HSlider}"
                     FontSize="36"
                     VerticalAlignment="Top"
                     TextAlignment="Center"
                     Width="436" />
            <Slider x:Name="HSlider" Orientation="Horizontal"
                    HorizontalAlignment="Left"
                    Height="172"
                    Margin="10,200,0,0"
                    VerticalAlignment="Top"
                    Width="436"
                    LargeChange="10"
                    SmallChange="1"
                    Minimum="0"
                    Maximum="100"
                    Value="50"

                    />
        </Grid>

See, the change we made here is that we changed the text property of the textblock into Text=”{Binding Value, ElementName=HSlider}” . Here, we binded the Value property of the Element HSlider.

😀 See? It’s really easy and see how much clean it looks now, all our job is done by only one line. That’s the magic of data binding.
wp_ss_20131004_0002

So, this is it for now, Next we’re gonna talk a little about DataConverters. Till then ciao!

Data binding – loaded

Back to code talks, yay! The last two posts were all about my daily adventures and experience (boring! 😡 ). FINALLY, we’re back to talk about code again. Okay, lemme see what I did wrong on the last post. As it seems because of MVVM’s steep learning curve a lot of people complained me they are not getting stuff properly in their head. So, let’s make it going. Shall we? Let’s break down stuffs a bit.

Let’s get into Data Binding a bit more. What’s data binding. If we remember our very own View-Model-ViewModel then data binding is what shows a Model’s properties on view. What am I meaning actually? Lets think of a data source that provides a list of persons to an app’s view. So, the model would contain a person’s basic properties, like name, age, height etc. A very important point to ponder here is model is not always the data source itself, it is the template of data in most of the times. So, its properties gets shown in the view i.e. in this case a person’s name, age, height would be shown. And thats in the simplest sense binding. It allows the view to form a bond with the model. 🙂 Trust me, that’s the simplest way I can describe data binding.

So, for all the people who are reading this, let me utter the words of  Jesse Liberty,

  • Data binding is not hard to understand
  • Neither hard to implement

SO, DONT RUN AWAY MAN! YOU ARE BETTER THAN THIS!

So, lets get into it. As this is one of the posts of my current series of MVVM I would definitely keep it on track of it. Lets start with a very basic view.

 <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="Data Bidning Loaded" Style="{StaticResource PhoneTextNormalStyle}" />
            <TextBlock x:Name="PageTitle" Text="DataBinding" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="Name" Text="Name" VerticalAlignment="Top" Width="450" />
            <TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="Age" Text="Age" VerticalAlignment="Top" Width="450" />
            <TextBox Height="72" HorizontalAlignment="Left" Margin="0,284,0,0" Name="Height" Text="Height" VerticalAlignment="Top" Width="450" />
        </Grid>
    </Grid>

Before we get into what we wrote let’s have a peel how it looks

DataBindingSimple1

Pretty basic ha? We need basic for this stage. So, if you look into the view you will see we practically did nothing. We imported three textbox controls and named them Name, Age and Height and filled them up with the same text. Even simple might get blushed seeing this. Cause this is simpler than the word simple. 😛

View is done, next we need a model. It’s gonna be a simple one too. Lets look our simplest Person model.

namespace DataBindingSimple
{
    class PersonModel
    {
        public string Name { get; set; }
        public string Age { get; set; }
        public string Height { get; set; }
    }
}

For the sake of the simplicity we’re gonna use the .cs file attached with the view i.e. the MainPage.xaml.cs here. We’re not gonna create  a seperate viewmodel for now as our purpose is to understand data binding properly first.

Lets see that first

namespace DataBindingSimple
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor

        PersonModel _personModel;

        public MainPage()
        {
            InitializeComponent();
            Loaded += MainPage_Loaded;

        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            _personModel = new PersonModel()
            {
                Name="Prateek",
                Age="23",
                Height="5.5"
            };

            SetDataContext();

        }

        private void SetDataContext()
        {
            ContentPanel.DataContext = _personModel;
        }

    }
}

Well, if we look into what we have just wrote, we’ll see there’s nothing new here. We added a PersonModel object as the DataContext of ContentPanel in the MainPage Loaded event. Wait, wait, wait, DataContext? What on god’s name is that?

To understand the concept of DataContext is to understand where the data comes from to the view. Obviously the data source and what it looks like or what is the template of the data. Of course its our model. Applying  a DataContext to something is to explicitly declare that the data that would be shown in the control comes from that DataContext. If you understand what Im saying then in the simplest sense DataContext is the source of the data. It can be a list, database object, a simple object like we used here. As long as it has data in the template we want , I mean in the model we described, we don’t have to worry about the view. 🙂
So, what we did here, we created a simple PersonModel object and declared it as DataContext of ContentPanel. Why? Because ContentPanel holds the three textboxes we want to show our data. So, the data should go there and as the ContentPanel is the container of those three textboxes it’s awarded the DataContext. Seems a bit clear now?

Is it supposed to work now? Shall we see my name, age and height in the three textboxes in the view now? The answer is obviously NO! We won’t. Why?
BECAUSE WE DIDN’T BIND THE DATA, DUH!

So, lets bind the data, shall we? Lets see how we bind the three properties of PersonModel in the three textboxes in the view. As we will only change the ContentPanel, lets see it below

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="Name" Text="{Binding Name}" VerticalAlignment="Top" Width="450" />
            <TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="Age" Text="{Binding Age}" VerticalAlignment="Top" Width="450" />
            <TextBox Height="72" HorizontalAlignment="Left" Margin="0,284,0,0" Name="Height" Text="{Binding Height}" VerticalAlignment="Top" Width="450" />
        </Grid>

The only thing that has changed is the text property of all the three textboxes. As we wanted to show the name property of the model in the first textbox we wrote:

<TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="Name" Text="{Binding Name}" VerticalAlignment="Top" Width="450" />

Look into the snippet Text={Binding Name}. Here Binding Name means we are binding the name property of the DataContext to the textbox. And what was the DataContext? Yes! The PersonModel object we assigned as DataContext a while ago.

Let’s see whether it works or not.

DataBindingSimple2

Yay! it does! So, you see Data Binding is practically very very easy. All you need to know is where is to bind something and what to bind. 🙂

I really wanted to talk a bit more but as I see long tutorials kind of takes people’s interest away from it now – a – days. So, thats it for today.

Next, we’re gonna talk about

  • Data Binding with INotifyPropertyChanged
  • Data Binding Modes
  • Element Binding
  • Data Converters

Don’t worry, I wont write these in a single one of course, learned my lesson from the last one. I would try to break these up into short ones.

So, until the next one, ciao!

Data Binding in MVVM – Bind views with viewmodels!

if(you_liked_app_philosophy)
start_here;else
goto Serious_talks;

So as per said in my last write up, Im supposed to give a glimpse on how viewmodel talks with views and how models supply them data. Im now gonna get straight back to the car scenario. Think of that car again. We had three parts, the engine (model), the body (view) and the driver (the viewmodel). You drive well, your car seems nice and clean, you roughhouse, eh! you might make it work on the outside but someday when you feel like upgrading that stuff, the only thing you’re gonna say, “what on earth did I do there”? If you ask me how do I know this? Brother I did the same mistake over and over again. (Yes, as per description of insanity from Far Cry 3, I was insane!)

So, the part I want to say here, your cars body will say how you drive. If it’s nice shiny and clean it says you’re a clear one, if it isn’t it says something else. So, the body (view) shows the signs you(viewmodel) leave on it. And how you bind it? Press the buzzer please!

“Data Binding” you say sire? You’re exactly right me lord.

Let’s Dive in.

Serious_talks:

Okay the serious stuff is in. I started with a pretty standard XAML (I believe you’ve met with standard Windows Phone development process, if you didn’t, you should and come back here). I added a panorama control, renamed it’s title to Star Cineplex. I added two panoramaitem control to cover “Now Showing” and “Coming Soon”. Pretty basic stuff actually. So, the xaml looks like below:

<phone:PhoneApplicationPage
x:Class="Star_Cineplex.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">

<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>

</Grid.RowDefinitions>

<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:Panorama Title="Star Cineplex">
<phone:PanoramaItem Header="Now Showing">
<ListBox Name="NowShowingList"  >

</ListBox>
</phone:PanoramaItem>
<phone:PanoramaItem Header="Coming Soon">

</phone:PanoramaItem>
</phone:Panorama>

</Grid>

</Grid>

</phone:PhoneApplicationPage>

So I guess it looks pretty simple to you.  You might want to look into the Listbox named “NowShowingList” as magic is gonna happen there. So, yes, the viewmodel mostly talks with view through data binding. . And Im not gonna tell much on data binding, so you should go for some basic data binding tutorials first. Without it, all of these would seem nonsense to you. True Story!

Let’s provide a dummy model. The model is nothing but a class who states how the actual data is represented. Let’s make a very simple Movie class. Shall we?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Star_Cineplex
{
    class Movie: INotifyPropertyChanged
    {
        private string name;
        private int year;

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                if (this.name != value)
                {
                    this.name = value;
                    this.RaisePropertyChanged("Name");
                }
            }
        }

        public int Year
        {
            get
            {
                return this.year;
            }
            set
            {
                if (this.year != value)
                {
                    this.year = value;
                    this.RaisePropertyChanged("Year");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }
}

Lets have a quick talk on the model then. The first thing you need to notice is the use of the INotifyPropertyChanged interface use. This very interface works as a secret serum for almost everything written on a MVVM app. You might ask why? This guy pokes you when a property changes its value in the class its implemented. Like if something changes the year property of the Movie class, this guy will jump up and say “Hello, somebody just changed the year property, care to do something?” Funny, ha? As funny as it sounds, believe me, this is one of the guys who you would see most in MVVM. So, lets have a lil discussion on this interface.

INotifyPropertyChanged interface basically raises an event named PropertyChanged. All you have to do is declare the event explicitly along with a method that will be executed generally for all properties that are monitored for a change. The method is optional if you’re cool with anonymous functions or lambda expressions. 😉

If you’re not, don’t leave. I’m even breaking it more up for you. You see in the set {} method of the property Year and Name whenever I found a change in the value I invoked the RaisePropertyChanged method to invoke the event to let the user know something has changed the property. We’ll actually go for a template or definite interfaces for models later so we don’t have to do this every time we write a model. But that’s later. Let’s focus on this simple area right now. 🙂

So, the model is pretty simple as it seems, so for now let’s forget the model, we’re gonna provide sample data here somehow to test how things work within the view and viewmodel. So, we need a viewmodel first. Don’t we? I’m posting a very basic viewmodel here. Later we would organize and sanitize the workflow more so we can extend stuff fast. But for now, for clarity’s sake let’s keep it very simple. Don’t worry the explanation comes just after. I believe the code talks more to a developer than anything.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.Windows.Input;

namespace Star_Cineplex
{
    class MovieViewModel
    {
        private ObservableCollection<Movie> movieDataSource;
        private ICommand loadDataCommand;

        public MovieViewModel()
        {
            this.movieDataSource = new ObservableCollection<Movie>();
            LoadData();
        }

        private void LoadData()
        {
            this.movieDataSource.Add(new Movie() { Name="Despicable Me 2", Year=2013});
            this.movieDataSource.Add(new Movie() { Name = "Man Of Steel", Year = 2013 });
            this.movieDataSource.Add(new Movie() { Name = "Wolverine", Year = 2013 });
        }

        public ObservableCollection<Movie> MovieDataSource
        {
            get
            {
                if (this.movieDataSource == null)
                {
                    this.movieDataSource = new ObservableCollection<Movie>();
                }
                return this.movieDataSource;
            }
        }

    }
}

I believe this is by far the simplest Viewmodel you can write. You see, all I did is I populated the MovieDataSource list with some data.

So, if you read the link I gave you before on Data Binding you’d might ask why Im not yet binding? Let’s do that! Remember the ListBox named “NowShowingList”? Change it into this one below:

<ListBox Name="NowShowingList" ItemSource={Binding MovieDataSource}  >
<ListBox.ItemTemplate>
 <DataTemplate >
 <StackPanel>
 <TextBlock Text="{Binding Name}" FontSize="{StaticResource PhoneFontSizeLarge}"></TextBlock>
 <TextBlock Text="{Binding Year}"></TextBlock>
 </StackPanel>
 </DataTemplate>
</ListBox.ItemTemplate>
</Listbox>

Wait, wait, wait! What did I do here? The first change you will see that I declared the itemsource of the listbox and I binded it with MovieDataSource, the one in our ViewModel!
This is done to show the movie list we created into the ListBox.

You might ask why did I use ObservableCollection? The interesting part is whenever you bind an ObservableCollection object as a ListBox’s itemsource, you dont have to worry about any changes in the list, the UI will adjust the changes automatically, no hassle needed! 😀 So, I mean if somehow the ObservableCollection gets bigger, the list in the UI will automatically grow bigger! So, if you add/remove a movie in the MovieDataSource, the NowShowingList ListBox will automatically grow bigger.

And I defined a data template to show the data. The datatemplate actually defines how each of your rows of your listbox will look like. I only used two texblocks here. And see! I binded the first one with Name and the second one with Year! Why? Because remember what was in the MovieDataSource? Yes, our model movie objects. It had two properties, Name and Year. We want both of them in our list. So, we binded both of them.

Now the question rises. Is this all? Aren’t we forgetting something?

Yes we are actually forgetting one thing. Kindly open the MainPage.xaml.cs and add the DataContext like this.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Star_Cineplex.Resources;

namespace Star_Cineplex
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            this.DataContext = new MovieViewModel();

        }

    }
}

So, what is the DataContext? the DataContext is the glue that holds them all. DataContext is usually defined by ViewModels as they provide the representable data to the view. I could’ve shown you many ways to bind data to the view but choosing a very simple example like this had only one objective and that is to let you know in MVVM to bind your view to viewmodel you only have to assign the DataContext. The rest is a breeze!

One other thing! I used a INotifyPropertyChanged in my model but never actually used it. We’ll continue this journey a bit more with ICommand usage and of course more binding usage with INotifyPropertyChanged interface in the upcoming ones.

Oh! This is how it looks now!

Screenshot

So, until next time, goodbye pals!