博客园  :: 首页  :: 联系 :: 订阅 订阅  :: 管理

WF4 AttachedPropertiesService

Posted on 2009-12-07 21:32  生鱼片  阅读(930)  评论(1编辑  收藏  举报

在运行时给某个实例注入附件属性,主要有三个类:AttachedPropertiesService AttachedProperty AttachedProperty<T>

下面是测试程序:

using System;

using System.Activities.Presentation;

using System.Activities.Presentation.Model;

using System.Collections.Generic;

using System.Linq;

 

namespace AttachedPropertiesBlogPosting

{

    class Program

    {

        static void Main(string[] args)

        {

            EditingContext ec = new EditingContext();

            ModelTreeManager mtm = new ModelTreeManager(ec);

            mtm.Load(new object[] { new Dog { Name = "Sasha", Noise = "Snort", Age = 5 },

                                    new Cat { Name="higgs", Noise="boom", Age=1 } });

            dynamic root = mtm.Root;

            dynamic dog = root[0];

            dynamic cat = root[1];

          

            ModelItem dogMi = root[0] as ModelItem;

            ModelItem catMi = root[1] as ModelItem;

 

            // Add an attached Property

            AttachedProperty<bool> ap = new AttachedProperty<bool>

            {

                IsBrowsable = true,

                Name = "IsAnInterestingDog",

                Getter = (mi => mi.Properties["Name"].ComputedValue.ToString() == "Sasha"),

                OwnerType = typeof(Dog)

            };

            ec.Services.Publish<AttachedPropertiesService>(new AttachedPropertiesService());

            AttachedPropertiesService aps = ec.Services.GetService<AttachedPropertiesService>();

            aps.AddProperty(ap);

 

            Console.WriteLine("---- Enumerate properties on dog (note new property)----");

            dogMi.Properties.ToList().ForEach(mp => Console.WriteLine(" Property : {0}", mp.Name));

 

            Console.WriteLine("---- Enumerate properties on cat (note  no new property) ----");

            catMi.Properties.ToList().ForEach(mp => Console.WriteLine(" Property : {0}", mp.Name)); 

 

            AttachedProperty<bool> isYoungAnimal = new AttachedProperty<bool>

            {

                IsBrowsable = false,

                Name = "IsYoungAnimal",

                Getter = (mi => int.Parse(mi.Properties["Age"].ComputedValue.ToString()) < 2)

            };

 

            aps.AddProperty(isYoungAnimal);

 

            // expect to not see isYoungAnimal show up

            Console.WriteLine("---- Enumerate properties on dog  (note isYoungAnimal doesn't appear )----");

            dogMi.Properties.ToList().ForEach(mp => Console.WriteLine(" Property : {0}", mp.Name));

            Console.WriteLine("---- Enumerate properties on cat (note isYoungAnimal doesn't appear )----");

            catMi.Properties.ToList().ForEach(mp => Console.WriteLine(" Property : {0}", mp.Name));

 

            Console.WriteLine("---- get attached property via GetValue ----");

            Console.WriteLine("getting non browsable attached property on dog {0}", isYoungAnimal.GetValue(dogMi));

            Console.WriteLine("getting non browsable attached property on cat {0}", isYoungAnimal.GetValue(catMi));

 

 

            // now, let's do something clever with the setter.

            Console.WriteLine("---- let's use the setter to have some side effect ----");

            isYoungAnimal.Setter = ((mi, val) => { if (val) { mi.Properties["Age"].SetValue(10); } });

            isYoungAnimal.SetValue(cat, true);

            Console.WriteLine("cat's age now {0}", cat.Age);

 

            // now, let's have a browesable one with a setter.

            // this plus dynamics are a mini "macro language" against the model items

 

            List<Object> FavoriteAnimals = new List<object>();

 

            // we maintain state in FavoriteAnimals, and use the getter/setter func

            // in order to query or edit that collection.  Thus changes to an "instance"

            // are tracked elsewhere.

            AttachedProperty<bool> isFavoriteAnimal = new AttachedProperty<bool>

            {

                IsBrowsable = false,

                Name = "IsFavoriteAnimal",

                Getter = (mi => FavoriteAnimals.Contains(mi)),

                Setter = ((mi, val) =>

                {

                    if (val)

                        FavoriteAnimals.Add(mi);

                    else

                    {

                        FavoriteAnimals.Remove(mi);

                    }

                })

            };

            aps.AddProperty(isFavoriteAnimal);

            dog.IsFavoriteAnimal = true;

            // remove that cat that isn't there

            cat.IsFavoriteAnimal = false;

            cat.IsFavoriteAnimal = true;

            cat.IsFavoriteAnimal = false;

            Console.WriteLine("Who are my favorite animals?");

            FavoriteAnimals.ForEach(o => Console.WriteLine((o as ModelItem).Properties["Name"].ComputedValue.ToString()));

            Console.ReadLine();

        }

    }

 

    public class Dog

    {

        public string Name { get; set; }

        public string Noise { get; set; }

        public int Age { get; set; }

    }

 

    public class Cat

    {

        public string Name { get; set; }

        public string Noise { get; set; }

        public int Age { get; set; }

    }

}

还可以用XAML的方式来显示属性值:

增加一个下面的Helper

public class Comment

    {

        static AttachableMemberIdentifier CommentTextName = new AttachableMemberIdentifier(typeof(Comment), "CommentText"); 

        public static object GetCommentText(object instance)

        {

            object viewState;

            AttachablePropertyServices.TryGetProperty(instance, CommentTextName, out viewState);

            return viewState;

        } 

        public static void SetCommentText(object instance, object value)

        {

            AttachablePropertyServices.SetProperty(instance, CommentTextName, value);

        }

 

    }

代码如下:

  AttachableMemberIdentifier ami = new AttachableMemberIdentifier(typeof(Comment), "CommentText");

            Dog newDog = new Dog { Age = 12, Name = "Sherlock", Noise = "Hooowl" };

            AttachablePropertyServices.SetProperty(newDog, ami, "A very good dog");

            string s = XamlServices.Save(newDog);

            Console.WriteLine("XAML");

            Console.WriteLine(s);

            Dog aSecondNewDog = XamlServices.Load(new StringReader(s)) as Dog;

            string outter;

            AttachablePropertyServices.TryGetProperty(aSecondNewDog, ami, out outter);

            Console.WriteLine("read out: {0}", outter);

输出:

XAML

<Dog

     Age="12"

     Comment.CommentText="A very good dog"

     Name="Sherlock"

     Noise="Hooowl"      xmlns="clr-namespace:AttachedPropertiesBlogPosting;assembly=AttachedPropertiesBlogPosting" />

read out: A very good dog

代码如下:

AttachedProperty<string> Comment = new AttachedProperty<string>

            {

                IsBrowsable = true,

                Name = "Comment",

                Getter = (mi =>

                {

                    string temp;

                    AttachablePropertyServices.TryGetProperty<string>(mi.GetCurrentValue(), ami, out temp);

                    return temp;

                }),

                Setter = ((mi, val) => AttachablePropertyServices.SetProperty(mi.GetCurrentValue(), ami, val))

 

            };

            aps.AddProperty(Comment);

            dogMi.Properties["Comment"].SetValue("I think I like that dog");

            string xaml = XamlServices.Save(dogMi.GetCurrentValue());

            Console.WriteLine("XAML");

            Console.WriteLine(xaml);

            Console.ReadLine();

 

输出:

<Dog

   Age="5"

   Comment.CommentText="I think I like that dog"

   Name="Sasha"

   Noise="Snort"    xmlns="clr-namespace:AttachedPropertiesBlogPosting;assembly=AttachedPropertiesBlogPosting" />

代码来源:

http://blogs.msdn.com/mwinkle/archive/2009/12/06/wf4-design-time-attachedpropertiesservice-and-attached-properties.aspx