没有WPF新东西,略过。
第2章
1)Background是一个Brush对象,而不是Color对象:
this.Background = new SolidColorBrush(Colors.Black);
而不可以:
this.Background = Colors.Black;
2)Brush相关的类,都位于System.Windows.Media中:
结构:
Brush(抽象类)
GradientBrush(抽象类)
LinearGradientBrush
RadialGradientBrush
SolidColorBrush
TileBrush(抽象类)
DrawingBrush
ImageBrush
VisualBrush
3)Freezable类
因为Brush继承自Freezable类,实现了Chenged事件,brush只要一有改变,就会触发该事件,客户区就会被重绘。
以下语句
brush = Brushes.Black;
也能产生
brush = new SolidColorBrush(Colors.Black);
的效果。唯一的区别,前者是利用Brushes类的静态只读属性取得的SolidColorBrush对象,处于“冻结”状态,不能再被改动——这种“冻结”机制派生于Freezable类,大大提高了效率。
那么,以下语句的搭配就会运行期报错:
brush = Brushes.Black;
Color clr = Color.FromRgb(1, 2, 3);
Brush.Color = clr;
为了解决这个问题,我们要制造一个没有冻结的复制版本,取代第一条语句:
brush = Brushes.Black.Clone();
其实,这一句,才和new SolidColorBrush(Colors.Black);是等效的。
此外,从SystemColors返回的系统级笔刷对象也都是冻结的。
4)渐变笔刷之:LinearGradientBrush
默认Point坐标使用相对坐标:左上角(0, 0),右下角(1, 1),其间所有Point的坐标都小于1。
也可以指定Point使用决定坐标定位,这是一个MappingMode枚举值。我们可以这样设置Brush笔刷对象的这个属性:
brush.MappingMode = BrushMappingMode.Absolute; //默认值为RelativeToBoundingBox
LinearGradientBrush的最简单形式,四个参数,两个Color和两个Point,表现为构造函数:
new LinearGradientBrush(Colors.Red, Colors.Black, new Point(0, 0), new Point(1, 1)
Colors.Red参数对应new Point(0, 0)参数,
Colors.Black参数对应new Point(1, 1)参数,
此外,也可以取代Point,而使用angle:以360度为一周。
GradientSpreadMethod枚举:
brush.SpreadMethod = GradientSpreadMethod.Pad;
负责填充剩余的区域,有三个值(假设由Red到Blue渐变):
Pad,默认值,剩余区域延续之前的颜色。
Reflect,剩余区域继续渐变,没有突变,为此要逆转。
Repeat,剩余区域继续渐变,有突变。与上面的区别我会把图补上。
LinearGradientBrush仅有的两个属性:StartPoint和EndPoint,从而确定brush的范围。
GradientStops属性
GradientStops,为渐变添加更多的颜色,而不仅局限于开始和结束两种,这是一个GradientStopCollection集合,其中的元素是GradientStop。
GradientStops的构造函数:new GradientStop(Colors, Offset)
这里Offset表示在StartPoint往EndPoint的方向长度为L的地方。L的计算公式:
L = (EndPoint - StartPoint) * Offset
5)渐变笔刷之:RadialGradientBrush
RadialGradientBrush类似于LinearGradientBrush,
没有StartPoint和EndPoint。
有3个属性Center,RadiusX和RadiusY,默认值都是0.5;
有一个GradientOrigin属性,作为渐变发生的原点,默认值都是(0.5, 0.5)。
6)传统.NET中的三种Timer,其中只有System.Windows.Forms中的Timer的Tick事件是发生在同一个当前主线程中(其他两个Timer在System.Threading和System.Timers中,它们的Tick事件都发生在不同的线程中)。
在WPF中,要使用System.Windows. Threading中的DispatcherTimer,才能在主线程中控制Freeable对象——因为Freeable创建于主线程。
7)总结,Window中有四个属性是Bursh类型的:
Background、Foreground以及OpacityMask、BorderBrush
第3章 内容
1)Content,Window最重要的属性,决定在窗口中显示什么东西,Object类型,即可以放置类型对象,当然Window中不能放置Window,因为Window必须是根元素。
2)Content属性中的Object分为两类:字符串,派生于UIElement的可视化元素。
在WPF中,UIElement很重要,用来实现键盘、鼠标等事件的处理,它有一个OnRender方法。
派生于UIElement的类,重写OnRender方法,可以自定义新的绘图:
于是可以直接使用这个SimpleEllipse,并作为Content显示:
SimpleEllipse elip = new SimpleEllipse();
Content = elip;
3)FrameworkElement是直接派生于UIElement的唯一类。而WPF中所有的元素都派生于FrameworkElement,这样UIElement就做到了最大化的抽象,如果以后有了新的框架,如WPF2,我们可以另建派生于UIElement的类FrameworkElement2,然后重新派生新的元素。
4)不要混淆ContentElement和ContentControl。
ContentControl是控件,具有Content属性。
ContentElement只是其他控件的一部分。
第4章 按钮及其他控件
1)Command命令
基于一个单一点来路由控件的消息,为此在ButtonBase类和MenuItem类中定义了Command属性。我们可以将Button的Command属性设置为以下5个类的静态属性:
ApplicationCommands、ComponentCommands、MediaCommands、NavigationCommand——以上4个类属于System.Windows.Input
EditingCommands——属于System.Windows.Document
这些类的静态属性都为RoutedUICommand类型,后面将会演示如何自定义一个RoutedUICommand类型。
使用如下:
button1.Command = ApplicationCommands.Paste;
CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, PasteOnExecute, PasteCanExecute));
对应的两个事件处理器如下:
一定要在PasteCanExecute中判断是否支持当前按钮是否有效,比如说当前剪切板中有一幅图片,则PasteCanExecute会将e.CanExecute设置为false,按钮就会立刻被禁用(disabled)
这样,这个ApplicationCommands.Paste可以在很多地方使用,只是在不同地方,指定的处理方法不同
我们可以指定按钮的文字设置为该命令的标准文字,如下显示“粘贴”或“Paste”:
button1.Content = ApplicationCommands.Paste.Text;
2)ToggleButton
ToggleButton不是抽象类,可以用来代替它的子类RadioButton或CheckBox控件。它也有IsChecked属性,表现为按钮凸出还是凹陷两种样式,注意到这是一个可空类型,所以获取到它的值后要进行强制类型转换:
(bool)btn.IsChecked
对于派生于此的RadioButton或CheckBox控件,它们的IsChecked属性也是要这样处理。空值,即“是”与“不是”的第三种选择:“取消选择”,在XAML中表现为
<ToggleButton Name="r"IsChecked="{x:Null}" …>
在C#中,即:
r.IsChecked = null;