在运行时给某个实例注入附件属性,主要有三个类: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
{
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" />
代码来源:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
2008-12-07 在ASP.NET MVC中使用WF