zoukankan      html  css  js  c++  java
  • WPF程序设计 :第三章 内容的概念(The Concept of Content)

    Window类的Content是从ContentControl类继承来的。ContentControl继承自Control,而Window直接继承自ContentControl。ContentControl类存在的意义几乎就是为了定义Content property以及几个相关的property和方法。

    Content property被定义成Object类型,这似乎暗示着它可以是任何对象,事实也相去不远。"相去不远"是因为你不可以把Content property设定成另一个Window类型的对象。运行时会报错,异常信息提醒开发者:Window必须是"树根",而不可以是另一个Window对象的分支。

    实例程序-1:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Media;

    namespace PartThree
    {
        
    public class DisplaysomeText : Window
        {
            [STAThread]
            
    public static void Main()
            {
                Application app 
    = new Application();
                app.Run(
    new DisplaysomeText());
            }

            
    public DisplaysomeText()
            {
                Title 
    = "Display some Text";
                Content 
    = new int[57];//EventArgs.Empty;//DateTime.Now;//Math.PI;

                Brush brush 
    = new LinearGradientBrush(Colors.Black, Colors.White, new Point(00), new Point(11));
                Background 
    = brush;
                Foreground 
    = brush;
                FontFamily 
    = new FontFamily("Comic Sans MS");
                FontSize 
    = 50;
                SizeToContent 
    = SizeToContent.WidthAndHeight;
                BorderBrush 
    = Brushes.SaddleBrown;
                BorderThickness 
    = new Thickness(255075100);
            }
        }
    }

    SizeToContent = SizeToContent.WidthAndHeight;

    Window类的SizeToContent property造成窗口大小可以根据内容的尺寸作调整。

    实例程序 - 2:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;

    namespace PartThree
    {
        
    public class RecordKeyStrokes : Window
        {
            [STAThread]
            
    public static void Main()
            {
                Application app 
    = new Application();
                app.Run(
    new RecordKeyStrokes());
            }

            StringBuilder build 
    = new StringBuilder("text");

            
    public RecordKeyStrokes()
            {
                Title 
    = "Record Key Strokes";
                Content 
    = build;
            }

            
    protected override void OnTextInput(System.Windows.Input.TextCompositionEventArgs e)
            {
                
    base.OnTextInput(e);
                
    //string str = Content as string;
                if (e.Text == "\b")
                {
                    
    if (build.Length > 0)
                    {
                        build 
    = build.Remove(build.Length - 11);
                    }
                }
                
    else
                {
                    build.Append(e.Text);
                }
                Content 
    = null;
                Content 
    = build;
            }
        }
    }

    Content Property 真正需要的是本质上更图形化的东西,由UIElement继承而来的类的实例。

    在WPF中,UIElement是一个极为重要的类。它实现键盘、鼠标以及手写笔(stylus)事件的处理。UIElement类也包含一个很重要的方法,名为OnRender。这个方法被调用,以显示对象的外观。(待会有实例程序)

    (你可以看到在DrawingContent对象中包含很多Draw..的方法)

    在Content property的世界中,分成两组对象:一组继承自UIElement,另一组则不是。后面一组的显示结果,就是ToString方法的返回值;前面这一组,则是利用OnRender来显示。继承自UIElement的类(以及对象)被称为element。对这句话的理解参见实例程序-1和实例程序-2。

    唯一直接继承UIElement的类是FrameworkElement,在WPF中所有的element都是继承自FrameworkElement。理论上,UIELement提供关于关于用户界面和屏幕显示的必要结构。可以支持各种各样的编程框架(programming framework)。WPF正是这样的框架,它包含继承自FrameworkElement的所有类。

    一个重要的类 Image,它是继承自FrameworkElement的一个很常见的类型。下面是它的继承层次:

     

    Object

          DispatcherObject(abstract)

                 DependencyObject

                           Visual(abstract)

                                      UIElement

                                              FrameworkElement

                                                      Image

     

    Image(图像)类让你可以轻易地在文件(document)或者应用内包含影像。

    实例程序 - 3,image

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Media.Imaging;
    using System.Windows.Controls;
    using System.Windows.Media;

    namespace PartThree
    {
        
    public class ShowMyFace : Window
        {
            [STAThread]
            
    public static void Main()
            {
                Application app 
    = new Application();
                app.Run(
    new ShowMyFace());
            }

            
    public ShowMyFace()
            {
                Title 
    = "Show my face";

                Uri uri 
    = new Uri(@"D://MyFace.jpg");
                BitmapImage bitmap 
    = new BitmapImage(uri);
                Image img 
    = new Image();
                img.Stretch 
    = Stretch.None;
                img.HorizontalAlignment 
    = HorizontalAlignment.Center;
                img.VerticalAlignment 
    = VerticalAlignment.Center;
                img.Source 
    = bitmap;
                img.Margin 
    = new Thickness(19296480);
                
    //img.Width = 300;
                
    //img.Height = 500;
                Content = img;
                
    //SizeToContent = SizeToContent.WidthAndHeight;

                img.Opacity 
    = 0.5;

                Background
    =new LinearGradientBrush(Colors.Red,Colors.Blue,new Point(0,0),new Point(1,1));
                img.LayoutTransform 
    = new RotateTransform(45);
            }
        }
    }
    Uri uri = new Uri(System.IO.Path.Combine(Enviroment.GetEnviromentVariable("windir"),"Gone Fishing.bmp"));

    Enviroment.GetEnviromentVariable("windir")方法取出"windir"环境变量,其值看起来像是"C:\\WINDOWS"这样的字符串。Path Combine方法结合图片文件的路径名称和文件名,这样就不用费心正确地插入斜杠了。

    Image类不具有自己的Background和Foreground property,因为这两个property是由Control类所定义的,而Image并非继承自Control。在早期Winows API中,几乎屏幕上所有的东西,都被认为是控件(Control),现在却不是如此。

    控件是视觉对象(visual object),其特征是对用户的输入有反应,像Image这样的element,当然可以得到用户的输入,因为所有的键盘、鼠标、手写笔的输入事件都是由UIElement所定义的。

    下面是System.Windows.Shapes这个命名空间,它包含名为Shape的抽象类,以及6个子类。

    Object

          DispatcherObject(abstract)

                 DependencyObject

                           Visual(abstract)

                                      UIElement

                                              FrameworkElement

                                                      Shape(abstract)

                                                              Ellipse

                                                              Line

                                                              Path

                                                              Polygon(多边形)

                                                              Polyline(多叉线)

                                                              Rectangle               

         

    虽然Image是现实点阵图像(raster图像)的标准做法,这些Shape类实现了简单的二维(two-dimensional)矢量图(Vector graphic) 。线面的程序创建一个椭圆(Ellipse)类的对象。

    实例程序 - 4, Ellipse

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Shapes;
    using System.Windows.Media;

    namespace PartThree
    {
        
    public class ShapeAnEllipse : Window
        {
            [STAThread]
            
    public static void Main()
            {
                Application app 
    = new Application();
                app.Run(
    new ShapeAnEllipse());
            }

            Ellipse elips;

            
    public ShapeAnEllipse()
            {
                Title 
    = "Shape an Ellipse";
                elips 
    = new Ellipse();
                elips.Fill 
    = Brushes.AliceBlue;
                elips.StrokeThickness 
    = 24;
                elips.Width 
    = 300;
                elips.Height 
    = 300;
                elips.Stroke 
    = new LinearGradientBrush(Colors.CadetBlue, Colors.Chocolate, new Point(10), new Point(01));
                
    //elips.HorizontalAlignment = HorizontalAlignment.Stretch;
                
    //elips.VerticalAlignment = VerticalAlignment.Stretch;
                Content = elips;
            }

            
    protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
            {
                
    base.OnMouseDown(e);
                
    double a = elips.ActualHeight;
            }
        }
    }

    该椭圆会填满客户区。周长是1/4英寸粗且使用了渐变画刷。(椭圆内部使用的是AliceBlue画刷来着色,这个颜色是以美国总统罗斯福的女儿来命名的)。

    注意的是:不管是Shape类还是Ellispe类,都没有定义任何property可以让我们用来设定椭圆的尺寸,但是Ellispe类从FrameworkElement继承到的Width和Height property,这两个property正式作此用的:

      elips.Wdith = 300;

      elips.Height = 300; 

    上面实例程序,如何将Window的Conteng property 设定为字符串,以及如何设定此文字的font。然而,你直接设定到Content property的文字,总具有相同的格式,比方说,你无法将其中几个字设定格式如粗体或斜体。

    如果你需要这样,就不要将Content property设定成字符串,而不是设定成一个TextBlock类型的对象,请看下面实例程序:

    实例程序 - 5:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;

    namespace PartThree
    {
        
    public class FormatTheText : Window
        {
            
    public FormatTheText()
            {
            [STAThread]
            
    public static void Main()
            {
                Application app 
    = new Application();
                app.Run(
    new FormatTheText());
            }
                Title 
    = "Format The Text";

                TextBlock txt 
    = new TextBlock();
                txt.FontSize 
    = 32;
                txt.Inlines.Add(
    "This is some");
                txt.Inlines.Add(
    new Italic(new Run("italic")));
                txt.Inlines.Add(
    "text ,and this is some ");
                txt.Inlines.Add(
    new Bold(new Run("bold")));
                txt.Inlines.Add(
    "text,and let's cap it off  with some ");
                txt.Inlines.Add(
    new Bold(new Italic(new Run("bold italic"))));
                txt.Inlines.Add(
    "text.");
                txt.TextWrapping 
    = TextWrapping.Wrap;

                Content 
    = txt;
            }
        }
    }

    其实,当你将Content property设定成字符串,那么ContentControl(这是Window的祖先类)会先创建一个Text Block类型的对象,以实际显示出此字符串,Text Block类直接继承自FrameworkElement,它定义了Inlines property(类型为InlineCollection,这是Inline对象的collection)。

    TextBlock本省属于System.Windows.Controls命名空间。但是 Inline是属于System.Windows.Document命名空间,而且甚至不是继承自UIElement。下面是部分的类继承图,显示出Inline和它的 后代:

    Object

          DispatcherObject(abstract)

                 DependencyObject

                           ContentElement

                                      FrameworkContentElement

                                              TextElement(abstract)

                                                      Inline(abstract)

                                                              Run

                                                              Span

                                                                   Bold

                                                                   Italic

                                                                   UnderLine               

         

    你可能注意到这个类层次与之前的似乎有类似的结构 ---- ContentElement 和 FrameworkContentElement 类对比于 UIElement和FrameworkElement类。然而,ContentElement类不包含OnRender方法。继承自ContentElement的类所产生的对象,不会在屏幕上把自己画出来。它们却是要通过"继承自UIElement的类"才能在屏幕上达到视觉的演示,由"继承自UIElement的类"提供他们所欠缺的OnRender方法。

    还有一点,不要把ContentElement 类和ContentControl混为一谈。ContentControl是控件,像Window一样,可以具有Content property。就算 Content property是空的,ContentControl对象还是会在屏幕上显示自己。而ContentElment对象一定要是其他可以显示的对象的一部分(也就是说,必须是控件的内容),才能得以显示。

    类似UIElement类,ContentElement类定义了许多用户输入事件,可以把事件处理器(event handler)安装到"由TextBlock显示出来的" Inline elements上.下面的程序展示此技巧。

    实例程序 - 6:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;

    namespace PartThree
    {
        
    public class ToggleBoldAndOtalic : Window
        {
            [STAThread]
            
    public static void Main()
            {
                Application app 
    = new Application();
                app.Run(
    new ToggleBoldAndOtalic());
            }

            
    public ToggleBoldAndOtalic()
            {
                Title 
    = "Toggle Bold & Italic";

                TextBlock txt 
    = new TextBlock();
                txt.FontSize 
    = 32;
                txt.HorizontalAlignment 
    = HorizontalAlignment.Center;
                txt.VerticalAlignment 
    = VerticalAlignment.Center;

                Content 
    = txt;

                
    string strQuote = "To be, or Not to be, That is the question";
                
    string[] strWords = strQuote.Split();

                
    foreach (string str in strWords)
                {
                    Run run 
    = new Run();
                    run.Text 
    = str;
                    run.MouseDown 
    += new System.Windows.Input.MouseButtonEventHandler(run_MouseDown);
                    txt.Inlines.Add(run);
                    txt.Inlines.Add(
    " ");
                }
            }

            
    void run_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
                Run run 
    = sender as Run;

                
    if (e.ChangedButton == MouseButton.Left)
                    run.FontStyle 
    = run.FontStyle == FontStyles.Italic ? FontStyles.Normal : FontStyles.Italic;

                
    if (e.ChangedButton == MouseButton.Right)
                    run.FontWeight 
    = run.FontWeight == FontWeights.Bold ? FontWeights.Normal : FontWeights.Bold;
            }
        }
    }

    前面其实提到,窗口的Content property其实想要的是继承自UIElement类的实例,因为此类定义了一个名为OnRender的方法,负责在屏幕上显示此对象。

    下面这个实例程序,让SimpleEllipse继承自FrameworkElement(这是直接继承自UIElement类的唯一类别),他相当重要的OnRender方法予以override,以获得一个DrawingContent对象。通过此对象和DrwingEllipse方法就可以绘制椭圆了。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Shapes;

    namespace PartThree
    {
        
    public class SimpleEllispe : FrameworkElement
        {
            
    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
            {
                drawingContext.DrawEllipse(Brushes.Blue, 
    new Pen(Brushes.Blue, 24), new Point(RenderSize.Width / 2, RenderSize.Height / 2), RenderSize.Width / 2, RenderSize.Height / 2);
                drawingContext.
            }
        }

        
    public class RenderTheGraphic : Window
        {
            [STAThread]
            
    public static void Main()
            {
                Application app 
    = new Application();
                app.Run(
    new RenderTheGraphic());
            }

            
    public RenderTheGraphic()
            {
                Title 
    = "Render the Graphic";

                SimpleEllispe elips 
    = new SimpleEllispe();
                elips.Width 
    = 120;
                elips.Height 
    = 100;
                Content 
    = elips;
            }
        }
    }

    总结:虽然本章使用到了System.Windows.Controls命名空间的element,但是没有使用任何继承自Control的类(当然Window本省是个例外)。控件是设计来获得用户的输入,并作出反应的。下一章,我们来展开这一范畴。

  • 相关阅读:
    css实现鼠标悬浮字体流光背景模糊效果
    原生JS实现省市区(县)三级联动选择
    多线程的对象锁和类锁
    session、cookie与“记住我的登录状态”的功能的实现
    Java NIO FileVisitor 高效删除文件
    mysql 服务启动失败
    Http 协议详解
    设计模式 之 策略模式
    简单探讨 javascript 闭包
    数据库SQL优化大总结之 百万级数据库优化方案
  • 原文地址:https://www.cnblogs.com/Dlonghow/p/1283718.html
Copyright © 2011-2022 走看看