WPF+学习笔记.docx

上传人:b****4 文档编号:3812412 上传时间:2022-11-25 格式:DOCX 页数:71 大小:347.11KB
下载 相关 举报
WPF+学习笔记.docx_第1页
第1页 / 共71页
WPF+学习笔记.docx_第2页
第2页 / 共71页
WPF+学习笔记.docx_第3页
第3页 / 共71页
WPF+学习笔记.docx_第4页
第4页 / 共71页
WPF+学习笔记.docx_第5页
第5页 / 共71页
点击查看更多>>
下载资源
资源描述

WPF+学习笔记.docx

《WPF+学习笔记.docx》由会员分享,可在线阅读,更多相关《WPF+学习笔记.docx(71页珍藏版)》请在冰豆网上搜索。

WPF+学习笔记.docx

WPF+学习笔记

WPF学习笔记

目录

WPF学习笔记1

Application1

Dispatcher3

Navigation5

XAML9

DependencyProperty15

RoutedEvent20

Resource24

Binding31

Silverlight-Hello,World!

68

Application

和WinForm类似,WPF同样需要一个Application来统领一些全局的行为和操作,并且每个Domain中只能有一个Application实例存在。

和WinForm不同的是WPFApplication默认由两部分组成:

App.xaml和App.xaml.cs,这有点类似于DelphiForm,将定义和行为代码相分离。

当然,WebForm也采用了类似的方式。

XAML从严格意义上说并不是一个纯粹的XML格式文件,它更像是一种DSL,它的所有定义都直接映射成某些代码,只不过具体的翻译工作由编译器完成而已。

下面是一个简单的App定义。

publicpartialclassApp:

Application

{

}

当你在自动生成的Project代码中看到paritial时,应该下意识去找找"Thiscodewasgeneratedbyatool."……不过这次自动生成的代码存放位置更加古怪——obj\Debug\App.g.cs。

publicpartialclassApp:

System.Windows.Application

{

  [DebuggerNonUserCode]

  publicvoidInitializeComponent()

  {

    this.StartupUri=newSystem.Uri("Window1.xaml",System.UriKind.Relative);

  }

  [STAThread]

  [DebuggerNonUserCode]

  publicstaticvoidMain()

  {

    Appapp=newApp();

    app.InitializeComponent();

    app.Run();

  }

}

App.StartupUri用于设置MainWindow,App.Run()启动消息循环。

当然,还有那个STAThread,这意味着WPF依旧使用一个UIThread来处理UIMessage。

我们完全可以舍弃自动生成的代码,自己手工写一个App。

publicclassApp:

Application

{

  [STAThread]

  privatestaticvoidMain()

  {

    varapp=newApp();

    varwindow=newWindow{Title="WPF"};

    app.Run(window);

  }

}

Application提供了一些实用的属性和方法。

Current:

获取Domain中默认的Application实例。

MainWindow:

获取主窗口实例。

Windows:

获取所有被实例化的Window实例。

ShutdownMode:

指定Application.Shutdown方式,包括主窗体关闭,最后一个窗口关闭,以及手工调用Shutdown()。

Properties:

一个线程安全的全局字典,可用来存储一个公共信息。

Shutdown:

该方法终止ApplicationProcess,可向操作系统返回一个退出码。

我们依然可以使用Mutex来阻止运行多个实例。

privatevoidApplication_Startup(objectsender,StartupEventArgse)

{

  varcreatedNew=false;

  varname=Assembly.GetEntryAssembly().FullName;

  newMutex(true,name,outcreatedNew);

  

  if(!

createdNew)

  {

    MessageBox.Show("Thereisalreadyaninstancerunning,Exit!

");

    Application.Current.Shutdown();

  }

}

当然也可以用Windows属性判断窗体是否已经存在。

privatevoidbutton1_Click(objectsender,RoutedEventArgse)

{

  varwindow2=Application.Current.Windows.OfType().FirstOrDefault(w=>wisWindow2);

  if(window2==null)window2=newWindow2();

  window2.Show();

  window2.Activate();

}

---------------------无聊的分割线--------------------

迟到的笔记总算开始了,算是为Silverlight做准备吧。

Dispatcher

WPF使用一个专用的UI线程来完成界面的操作和更新,这个线程会关联一个唯一的Dispatcher对象,用于调度按优先顺序排列的工作项队列。

Application.Run()实际上就是对Dispatcher.Run()的间接调用。

Dispatcher通过循环来处理工作项队列,这个循环通常被成为"帧(DispatcherFrame)"。

Dispatcher.Run()创建并启动这个帧,这也是Application.Run()启动消息循环的最终途径。

publicsealedclassDispatcher

{

  [SecurityCritical,UIPermission(SecurityAction.LinkDemand,Unrestricted=true)]

  publicstaticvoidRun()

  {

    PushFrame(newDispatcherFrame());

  }

}

DispatcherFrame可以嵌套,并通过检查Continue属性来决定循环是否继续。

我们可以通过调用Dispatcher.ExitAllFrames()来终止所有的帧循环,当然这种编程方式并不可取,可能会造成一些意外出现。

与Dispatcher调度对象想对应的就是DispatcherObject,在WPF中绝大部分控件都继承自DispatcherObject,甚至包括Application。

这些继承自DispatcherObject的对象具有线程关联特征,也就意味着只有创建这些对象实例,且包含了Dispatcher的线程(通常指默认UI线程)才能直接对其进行更新操作。

当我们尝试从一个非UI线程更新一个标签,会看到一个如下的异常。

privatevoidbutton1_Click(objectsender,RoutedEventArgse)

{

  newThread(()=>this.label1.Content=DateTime.Now.ToString()).Start();

}

按照DispatcherObject的限制原则,我们改用Window.Dispatcher.Invoke()即可顺利完成这个更新操作。

privatevoidbutton1_Click(objectsender,RoutedEventArgse)

{

  newThread(()=>

  {

    this.Dispatcher.Invoke(DispatcherPriority.Normal,

      newAction(()=>this.label1.Content=DateTime.Now.ToString()));

  }).Start();

}

如果在其他项目(比如类库)中,我们可以用Application.Current.Dispatcher.Invoke(...)完成同样的操作,它们都指向UIThreadDispatcher这个唯一对象。

Dispatcher还提供了BeginInvoke这个异步版本。

privatevoidbutton1_Click(objectsender,RoutedEventArgse)

{

  newThread(()=>

  {

    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,

      newAction(()=>

      {

        Thread.Sleep(3000);

        this.label1.Content=DateTime.Now.ToString();

      }));

    MessageBox.Show("Hi!

");

  }).Start();

}

凡事都有例外,WPF还提供了一种继承自Freezable的类型,尽管Freezable也间接继承自DispatcherObject,但当这类对象从修改状态变成冻结状态时,它即变成自由线程对象,不在具有线程关联。

(有关Freezable详情可参考MSDN)

Navigation

互联网的兴起,造就和培养了一种新的用户交互界面——Page&Navigation。

无论是前进、后退还是页面,都完全是一个全新的门类,不同于以往的SDI/MDI。

WPF或者是它的简化版Silverlight都不可避免地遵从了这种改良的B/S模式,使用URI来串接UI流程。

NavigationService、Page、Hyperlink、Journal(日志/历史记录)是WPF整个导航体系的核心。

NavigationService提供了类似IEHost的控制环境,Journal可以记录和恢复相关Page的状态,我们通常会选用的宿主方式包括:

Browser(XBAP)和NavigationWindow。

1.NavigationWindow

NavigationWindow继承自Window,不知什么原因,我并没有在VS2008"NewItem..."中找到相关的条目,只好自己动手将一个Window改成NavigationWindow。

Window1.xaml

Class="Window1"

  xmlns="

  xmlns:

x="

  Title="Window1"Height="300"Width="300"WindowStartupLocation="CenterScreen"

  Source="Page1.xaml">

Source属性指定了该窗口的默认页面,当然,我们还要修改一下Window1.xaml.cs里的基类。

publicpartialclassWindow1:

NavigationWindow

{

  publicWindow1()

  {

    InitializeComponent();

  }

}

创建一个Page1.xaml,我们就可以像普通Window那样添加相关的控件和操作。

2.Hyperlink

超链接应该是我们最熟悉的一种导航方式。

Page1.xaml

Class="Learn.WPF.Page1"

  xmlns="

  xmlns:

x="

  Title="Page1">

  

    

      Page2

    

  

NavigateUri相当于"Htmla.href",当然我们也可以使用Hyperlink.Click事件,然后使用NavigationService来完成导航操作。

Page1.xaml

Page2

Page1.xaml.cs

privatevoidHyperlink_Click(objectsender,RoutedEventArgse)

{

  this.NavigationService.Navigate(newUri("Page2.xaml",UriKind.Relative));

}

Hyperlink还支持"test.htm#name"这样的导航定位方式,滚动页面直到某个特定名称的控件被显示。

Hyperlink的另外一个实用属性是Command,我们可以使用NavigationCommands中创建的一系列静态成员来执行一些常用操作。

Refresh

BrowseBack

BrowseForward

3.NavigationService

很多时候我们都需要使用NavigationService代替Hyperlink.NavigateUri,比如非默认构造的Page,动态确定目标页面等等。

我们可以使用Page.NavigationService或者NavigationService.GetNavigationService()获得NavigationService的实例引用(别忘了添加usingSystem.Windows.Navigation)。

publicpartialclassPage1:

Page

{

  privatevoidHyperlink_Click(objectsender,RoutedEventArgse)

  {

    varpage2=newPage2();

    page2.label1.Content="Beijing2008!

";

    this.NavigationService.Navigate(page2);

  }

}

除了Navigate(),还可以使用NavigationService的两个属性完成导航切换操作。

//this.NavigationService.Content=page2;

this.NavigationService.Source=newUri("Page2.xaml",UriKind.Relative);

NavigationService提供了大量的方法和时间来管理相关导航操作。

日志:

AddBackEntry、RemoveBackEntry。

载入:

Navigate、Refresh、StopLoading。

切换:

GoBack、GoForward。

事件:

Navigating(新导航请求时触发,可取消导航)……

我们也可以使用Application的相关事件来处理导航过程。

4.Journal

Journal相当于WebBrowser.History,它包含两个数据栈用来记录前进和后退页面的显示状态,每个相关Page都会对应一个JournalEntry。

日志状态自动恢复仅对单击导航条上前进后退按钮有效。

5.Page

有关Page本身的使用并不是本文的内容,我们此处关心的是它在导航过程中的生命周期。

在WPF中,Page注定是个短命鬼,无论我们使用导航还是后退按钮都会重新创建Page对象实例,然后可能是日志对其恢复显示状态。

也就是说日志只是记录了Page相关控件的状态数据,而不是Page对象引用(默认情况下)。

有两种方式来维持一个Page引用。

第一种就是我们自己维持一个Page引用,比如使用某个类似Application.Properties这样的容器。

privatevoidHyperlink_Click(objectsender,RoutedEventArgse)

{

  varpage2=Application.Current.Properties["page2"]asPage2;

  if(page2==null)

  {

    page2=newPage2();

    page2.label1.Content=DateTime.Now.ToString();

    Application.Current.Properties["page2"]=page2;

  }

  this.NavigationService.Navigate(page2);

  //this.NavigationService.Content=page2;

}

另外一种就是设置Page.KeepAlive属性,这样一来日志会记录该Page的引用,当我们使用前进后退按钮时,将不会再次创建该Page的对象实例。

Class="Learn.WPF.Page2"

  xmlns="

  xmlns:

x="

  Title="Page2"Loaded="Page_Loaded"

  KeepAlive="True">

有一点需要注意:

该方法仅对前进后退等日志操作有效。

如果我们使用HyperLink.NavigateUri或NavigationService.Navigate()导航时依旧会生成新的页面实例,并可能代替日志中最后一个同类型的对象引用记录。

另外,当多个页面存在循环链接时,会导致多个页面实例被日志记录,造成一定的内存浪费。

6.Frame

Frame的作用和HTML中的IFrame类似,我们可以用它在一个普通的Window或Page中嵌套显示其他的Page。

Class="Learn.WPF.Window1"

  xmlns="

  xmlns:

x="

  Title="Window1"Height="300"Width="300">

  

    

  

默认情况下,Frame会尝试使用上层页面(Page)或窗体(NavigationWindow)的日志,当然我们也可以使用JournalOwnership属性强行让Frame使用自己的日志导航。

Frame的另外一个作用就是可以导航到HTML页面,我们可以把它当作一个嵌入式IEWebBrowser来使用。

7.PageFunction

WPF提供了一个称之为PageFunction的Page继承类来实现类似HTMLshowModal的功能。

我们可以用它来收集某些数据并返回给调用页,当然这个封装其实非常简单,我们完全可以自己实现,无非是提供一个类似OnReturn的方法实现而已。

泛型参数T表示返回数据类型。

Page1.xaml.cs

publicpartialclassPage1:

Page

{

  privatevoidHyperlink_Click(objectsender,RoutedEventArgse)

  {

    varmodal=newPageFunction1();

    modal.Return+=(s,ex)=>this.label1.Content=ex.Result.ToString();

    this.NavigationService.Navigate(modal);

  }

}

PageFunction1.xaml.cs

publicpartialclassPageFunction1:

PageFunction

{

  privatevoidbutton1_Click(objectsender,RoutedEventArgse)

  {

    OnReturn(newReturnEventArgs(DateTime.Now.Millisecond));

  }

}

使用步骤:

(1)创建PageFunction对象实例,当然我们可以使用含参构造传递额外的数据;

(2)调用PageFunction.OnReturn()方法用来返回一个特定的结果包装对象——ReturnEventArgs

(3)调用者通过订阅Page

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1