NOTE: If you haven't read the first post in this series, I would encourage you do to that first, or check out the BabySmash category. Also check out http://windowsclient.net/ for more developer info on WPF.
注意:如果您还没有阅读本系列的第一篇文章,我建议您先阅读该文章,或者查看BabySmash类别。 另请访问http://windowsclient.net/以获取有关WPF的更多开发人员信息。
BACKGROUND: This is one of a series of posts on learning WPF. I wrote an application for my 2 year old using WPF, but as I'm a Win32-minded programmer, my working app is full of Win32-isms. It's not a good example of a WPF application even though it uses the technology. I'm calling on community (that's you, Dear Reader) to blog about your solutions to different (horrible) selections of my code. You can get the code http://www.codeplex.com/babysmash. Post your solutions on your blog, in the comments, or in the Issue Tracker and we'll all learn WPF together. Pick a single line, a section, or subsystem or the whole app!
背景:这是有关学习WPF的一系列文章之一。 我使用WPF为2岁的孩子编写了一个应用程序,但是由于我是位Win32程序员,所以我的工作应用程序充满了Win32-ism。 即使它使用WPF技术,也不是WPF应用程序的好例子。 我正在呼吁社区(即您,亲爱的读者)在博客中介绍您针对我的代码的不同(糟糕)选择的解决方案。 您可以获取代码http://www.codeplex.com/babysmash 。 将您的解决方案发布到您的博客,评论或问题跟踪器中,我们将一起学习WPF。 选择一条线,一个部分,子系统或整个应用程序!
BabySmash has a little mini-heirarchy of "Figures" that represent the Shapes on the screen, along with a little additional information like the name of the Figure ("square", "circle") as well as an English word for the color. I intend to internationalize it at some point.
BabySmash在屏幕上具有代表图形的“图形”微型层次结构,以及一些其他信息,例如图形名称(“正方形”,“圆圈”)以及英语的颜色。 我打算将其国际化。
Figure has been pretty simple so far and doesn't really do anything:
到目前为止,Figure很简单,实际上并没有做任何事情:
public abstract class Figure
{
private UIElement shape;
private readonly string name;
private readonly string color;
protected Figure(Brush fill, string name)
{
this.color = Utils.BrushToString(fill);
this.name = name;
}
public UIElement Shape
{
get { return shape; }
protected set { shape = value; }
}
public string Name { get { return name; } }
public string Color { get { return color; } }
}
Derived Shapes are mostly declarative, and very repetitive:
派生形状主要是声明性的,并且非常重复:
public class SquareFigure : Figure
{
public SquareFigure(Brush fill)
: base(fill, "square")
{
Shape = new Rectangle()
{
Fill = fill,
Height = 380,
Width = 380,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
}
public class StarFigure : Figure
{
public StarFigure(Brush fill)
: base(fill, "star")
{
Shape = new Star()
{
NumberOfPoints = 5,
Height = 400,
Width = 400,
Fill = fill,
StrokeThickness = 5,
Stroke = Brushes.Black,
};
}
}
Last post, we removed a bunch of the Style related stuff and put it into XAML markup as a shared Style application resource we could use all over. This makes things DRYer (Don't Repeat Yourself) but still something doesn't smell right.
上一篇文章,我们删除了一堆与Style相关的内容,并将其作为XAML标记作为共享的Style应用程序资源,我们可以全部使用。 这会使事情变干(不要重复自己),但仍然闻不到正确的气味。
I still have to grab the Style and pass the Fill along into the Shape property, and I do it for EVERY Shape. Meh. It's the same four lines over and over again.
我仍然必须获取Style并将Fill传递到Shape属性中,并且对每个Shape都要这样做。 嗯一遍又一遍是相同的四行。
public class SquareFigure : Figure
{
public SquareFigure(Brush fill)
: base(fill, "square")
{
Shape s = new Rectangle();
s.Style = Application.Current.Resources["square"] as Style;
s.Fill = fill;
Shape = s;
}
}
Ripe for refactoring I say. Note the call to base() in the Constructor. You'd be surprised how many people either don't know about base() or who knew and forgot. ;)
我说重构的时机已经成熟。 注意在构造函数中对base()的调用。 您会惊讶于有多少人对base()不了解,或者谁知道并忘记了。 ;)
Oddly, I was already passing Fill into the constructor, and then passing it up the hierarchy to the abstract base class Figure without thinking. This is very common when you slap code together then finally take a breath and LOOK at it. Ever more common when you have someone who isn't "into" the code just look over your shoulder and say "um, what's THAT?" You really can't overestimate how useful another set of eyes are. I did a quick SharedView with Jason this afternoon and his fresh eyes sped up my refactoring considerably.
奇怪的是,我已经将Fill传递给构造函数,然后不加考虑地将其沿层次结构传递给抽象基类Figure。 当您将代码拍到一起然后最后屏住呼吸并看一下时,这是很常见的。 当您遇到一个不“喜欢”代码的人时,通常会越过您的肩膀说“嗯,那是什么?”,这种情况越来越普遍。 您真的不能高估另一只眼睛的用处。 我今天下午和Jason做了一个快速的SharedView ,他新鲜的眼睛大大加快了我的重构速度。
public abstract class Figure
{
private readonly string name;
private readonly string color;
protected Figure(Brush fill, string name, Shape s)
{
this.color = Utils.BrushToString(fill);
this.name = name;
this.Shape = s;
s.Fill = fill;
s.Style = Application.Current.Resources[Name] as Style;
}
public UIElement Shape { get; protected set; }
public string Name { get { return name; } }
public string Color { get { return color; } }
}
Here we moved everything that was repeated (shared) up into the base class. The Shape property used the C# 3.0 property syntax that let us remove a field (it's generated now). Notice the use of the protected keyword on the setter.
在这里,我们将重复(共享)的所有内容移至基类中。 Shape属性使用C#3.0属性语法,该语法使我们可以删除字段(该字段现在已生成)。 注意在setter上使用protected关键字。
The only thing that "smells" bad about this for me is the call to Application.Current.Resources. This is the moral equivalent to HttpContext.Current as it's saying "reach out into the heavens that you ought not know about and pull a rabbit out of a hat" or, in this case, a resource out of Application.Resources. However, as far as I can tell, this is a minor sin, and a common one, unless I want to start passing all these bits of information around my hierarchy while trying to obey the Law of Demeter, which I'm arguably already breaking.
对此我唯一“闻”到不好的是对Application.Current.Resources的调用。 这在道德上等同于HttpContext.Current,因为它的意思是“伸出您不应该知道的天堂,将兔子从帽子里拉出来”,或者在这种情况下,将资源从Application.Resources中移除。 但是,据我所知,这是一个轻微的错误,也是一个普遍的错误,除非我想开始遵循遵从Demeter的定律来开始在我的等级体系中传递所有这些信息,但我可能已经打破了。
Regardless, suddenly my library of Figures becomes much simpler. Of course, adding new ones will be even simpler now. For example:
无论如何,突然之间,我的数字图书馆变得更加简单。 当然,现在添加新的将更加简单。 例如:
public class RectangleFigure : Figure
{
public RectangleFigure(Brush fill)
: base(fill, "rectangle", new Rectangle()){}
}
public class CircleFigure : Figure
{
public CircleFigure(Brush fill)
: base(fill, "circle", new Ellipse()){}
}
public class TriangleFigure : Figure
{
public TriangleFigure(Brush fill)
: base(fill, "triangle", new Polygon()){}
}
public class StarFigure : Figure
{
public StarFigure(Brush fill)
: base(fill, "star", new Star()){}
}
In the next post I'll refactor the factory that makes these figures into something that allows me to sleep at night. ;)
在下一篇文章中,我将重构使这些数字变成可以让我晚上睡觉的东西的工厂。 ;)
翻译自: https://www.hanselman.com/blog/learning-wpf-with-babysmash-pushing-things-up-a-level-with-another-set-of-eyes