一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

WPF 基礎(chǔ)到企業(yè)應(yīng)用系列4——WPF千年輪回

1.開(kāi)篇前言

     首先很高興這個(gè)系列能得到大家的關(guān)注和支持,基于對(duì)大家負(fù)責(zé)和對(duì)自己負(fù)責(zé)的態(tài)度,我會(huì)不斷努力寫(xiě)好這個(gè)系列,分享自己的微薄技術(shù)和經(jīng)驗(yàn),希望在幫助別人的同時(shí)也不斷提升自己。由于這篇文章很多(現(xiàn)已拆分成2篇,今天這篇只是其中之一),一共花了幾個(gè)個(gè)晚上的休息時(shí)間才完成,所以讀者花的時(shí)間長(zhǎng)了一些,也希望大家能夠見(jiàn)諒,這個(gè)系列以后會(huì)每周發(fā)三到四篇左右(主要是寫(xiě)一篇差不多要花幾晚上,感覺(jué)思維比較發(fā)散),除了講WPF技術(shù)本身之外,也會(huì)講一些項(xiàng)目具體開(kāi)發(fā),所以敬請(qǐng)關(guān)注。

    本篇文章取名為WPF千年輪回只因?yàn)閮蓚€(gè)原因:

  1. WPF和當(dāng)年Win32、WinForm等的到來(lái)頗為相似,只是在功能和體驗(yàn)上上進(jìn)行了提高,所以這是微軟產(chǎn)品上的一個(gè)輪回;
  2. WPF的學(xué)習(xí)過(guò)程和其他技術(shù)一樣,譬如ASP.NET,我們?cè)趯W(xué)習(xí)的時(shí)候會(huì)先要了解ASP.NET構(gòu)架(Http請(qǐng)求處理流程)、Pipeline、HttpHandler 和 HttpModule 等內(nèi)容,這和WPF的Application生命周期相對(duì)應(yīng),再如WPF的Window生命周期可以和ASP.NET的頁(yè)面生命周期相對(duì)應(yīng)等。當(dāng)然你也可以拿WinForm或者其他技術(shù)來(lái)舉例,這里這是闡述觀點(diǎn)。

    在前三篇文章中我們對(duì)WPF有了一個(gè)比較全面的認(rèn)識(shí),并且也通過(guò)一個(gè)基本的例子對(duì)比了WPF和之前的WinForm程序的區(qū)別和聯(lián)系。那么在本篇文章當(dāng)中,除了講一些理論知識(shí)外,更多的是用實(shí)際的代碼來(lái)驗(yàn)證這些理論。

2.本文提綱

· 1.開(kāi)篇前言

· 2.本文提綱

· 3.Application

· 4.Window

· 5.Dispatcher及多線程

· 6.類(lèi)繼承結(jié)構(gòu)

· 7.WPF的邏輯樹(shù)和視覺(jué)樹(shù)

· 8.本文總結(jié)

. 9.系列進(jìn)度

3.Application

    一.介紹

    WPF和 傳統(tǒng)的WinForm 類(lèi)似, WPF 同樣需要一個(gè) Application 來(lái)統(tǒng)領(lǐng)一些全局的行為和操作,并且每個(gè) Domain (應(yīng)用程序域)中只能有一個(gè) Application 實(shí)例存在。和 WinForm 不同的是 WPF Application 默認(rèn)由兩部分組成 : App.xaml 和 App.xaml.cs,這有點(diǎn)類(lèi)似于 Delphi Form(我對(duì)此只是了解,并沒(méi)有接觸過(guò)Delphi ),將定義和行為代碼相分離。當(dāng)然,這個(gè)和WebForm 也比較類(lèi)似。XAML 從嚴(yán)格意義上說(shuō)并不是一個(gè)純粹的 XML 格式文件,它更像是一種 DSL(Domain Specific Language,領(lǐng)域特定語(yǔ)言),它的所有定義都直接映射成某些代碼,只是具體的翻譯工作交給了編譯器完成而已。WPF應(yīng)用程序由System.Windows.Application類(lèi)來(lái)進(jìn)行管理。

    二.創(chuàng)建WPF應(yīng)用程序

    創(chuàng)建WPF應(yīng)用程序有兩種方式:

1、Visual Studio和Expression Blend默認(rèn)的方式,使用App.xaml文件定義啟動(dòng)應(yīng)用程序

    App.xaml文件的內(nèi)容大致如下所示:

7-4-2010 4-00-27 PM

2、可以自已定義類(lèi),定義Main方法實(shí)現(xiàn)對(duì)WPF應(yīng)用程序的啟動(dòng)

     在項(xiàng)目中添加一個(gè)類(lèi),類(lèi)的代碼如下,在項(xiàng)目選項(xiàng)中,設(shè)定此類(lèi)為啟動(dòng)項(xiàng)。

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;

namespace WPFApplications
{
///
///
Interaction logic for App.xaml
///
public partial class App : Application
{
[STAThread]
static void Main()
{
// 定義Application對(duì)象作為整個(gè)應(yīng)用程序入口
Application app = new Application();
// 方法一:調(diào)用Run方法,參數(shù)為啟動(dòng)的窗體對(duì)象 ,也是最常用的方法
Window2 win = new Window2();
app.Run(win);

// 方法二:指定Application對(duì)象的MainWindow屬性為啟動(dòng)窗體,然后調(diào)用無(wú)參數(shù)的Run方法
//Window2 win = new Window2();
//app.MainWindow = win;
//win.Show();
// win.Show()是必須的,否則無(wú)法顯示窗體
//app.Run();

// 方法三:通過(guò)Url的方式啟動(dòng)
//app.StartupUri = new Uri("Window2.xaml", UriKind.Relative);
//app.Run();
}
}
}

    三、Application應(yīng)用程序關(guān)閉

  
OnLastWindowClose(默認(rèn)值):最后一個(gè)窗體關(guān)閉或調(diào)用Application對(duì)象的Shutdown() 方法時(shí),應(yīng)用程序關(guān)閉。
OnMainWindowClose啟動(dòng)窗體關(guān)閉或調(diào)用Application對(duì)象的Shutdown()方法時(shí),應(yīng)用程序關(guān)閉。(和C#的Windows應(yīng)用程序的關(guān)閉模式比較類(lèi)似)
OnExplicitShutdown只有在調(diào)用Application對(duì)象的Shutdown()方法時(shí),應(yīng)用程序才會(huì)關(guān)閉。

     對(duì)關(guān)閉選項(xiàng)更改的時(shí)候,可以直接在App.xaml中更改:

<Application x:Class="WPFApplications.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window2.xaml"
ShutdownMode="OnExplicitShutdown">
<
Application.Resources>
Application.Resources>
Application>

   同樣你也可以在代碼文件(App.xaml.cs)中進(jìn)行更改,但必須注意這個(gè)設(shè)置寫(xiě)在app.Run()方法之前 ,如下代碼:
   app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
   app.Run(win);

   四、Application對(duì)象的事件

名稱(chēng)

描述

Activated

當(dāng)應(yīng)用程序成為前臺(tái)應(yīng)用程序時(shí)發(fā)生,即獲取焦點(diǎn)。

Deactivated

當(dāng)應(yīng)用程序停止作為前臺(tái)應(yīng)用程序時(shí)發(fā)生,即失去焦點(diǎn)。

DispatcherUnhandledException

在異常由應(yīng)用程序引發(fā)但未進(jìn)行處理時(shí)發(fā)生。

Exit

正好在應(yīng)用程序關(guān)閉之前發(fā)生,且無(wú)法取消。

FragmentNavigation

當(dāng)應(yīng)用程序中的導(dǎo)航器開(kāi)始導(dǎo)航至某個(gè)內(nèi)容片斷時(shí)發(fā)生,如果所需片段位于當(dāng)前內(nèi)容中,則導(dǎo)航會(huì)立即發(fā)生;或者,如果所需片段位于不同 內(nèi)容中,則導(dǎo)航會(huì)在加載了源 XAML 內(nèi)容之后發(fā)生。

LoadCompleted

在已經(jīng)加載、分析并開(kāi)始呈現(xiàn)應(yīng)用程序中的導(dǎo)航器導(dǎo)航到的內(nèi)容時(shí)發(fā)生。

Navigated

在已經(jīng)找到應(yīng)用程序中的導(dǎo)航器要導(dǎo)航到的內(nèi)容時(shí)發(fā)生,盡管此時(shí)該內(nèi)容可能尚未完成加載。

Navigating

應(yīng)用程序中的導(dǎo)航器請(qǐng)求新導(dǎo)航時(shí)發(fā)生。

NavigationFailed

應(yīng)用程序中的導(dǎo)航器在導(dǎo)航到所請(qǐng)求內(nèi)容時(shí)出現(xiàn)錯(cuò)誤的情況下發(fā)生。

NavigationProgress

在由應(yīng)用程序中的導(dǎo)航器管理的下載過(guò)程中定期發(fā)生,以提供導(dǎo)航進(jìn)度信息。

NavigationStopped

在調(diào)用應(yīng)用程序中的導(dǎo)航器的 StopLoading 方法時(shí)發(fā)生,或者當(dāng)導(dǎo)航器在當(dāng)前導(dǎo)航正在進(jìn)行期間請(qǐng)求了一個(gè)新導(dǎo)航時(shí)發(fā)生(沒(méi)大用到)。

SessionEnding

在用戶(hù)通過(guò)注銷(xiāo)或關(guān)閉操作系統(tǒng)而結(jié)束 Windows 會(huì)話時(shí)發(fā)生。

Startup

在調(diào)用 Application 對(duì)象的 Run 方法時(shí)發(fā)生。

應(yīng)用程序的事件處理可以:

1、在App.xaml中做事件的綁定,在App.xaml.cs文件中添加事件的處理方法

     在App.xaml文件中:

<Application x:Class="WPFApplications.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="Application_Startup"
Exit="Application_Exit"
DispatcherUnhandledException="Application_DispatcherUnhandledException">
<
Application.Resources>

Application.Resources>
Application>

    在App.xaml.cs文件中:

public partial class App : Application
{
[STAThread]
static void Main()
{
// 定義Application對(duì)象作為整個(gè)應(yīng)用程序入口
Application app = new Application();
// 方法一:調(diào)用Run方法,參數(shù)為啟動(dòng)的窗體對(duì)象 ,也是最常用的方法
Window2 win = new Window2();
app.Run(win);
}

private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{ }

private void Application_Exit(object sender, ExitEventArgs e)
{ }
}

2、在自定義的類(lèi)中可以做正常的C#的事件綁定:

public partial class App : Application
{
[STAThread]
static void Main()
{
// 定義Application對(duì)象作為整個(gè)應(yīng)用程序入口
Application app = new Application();
// 調(diào)用Run方法,參數(shù)為啟動(dòng)的窗體對(duì)象 ,也是最常用的方法
Window2 win = new Window2();
app.Startup += new StartupEventHandler(app_Startup);
app.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(app_DispatcherUnhandledException);
app.Run(win);
}

static void app_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
throw new NotImplementedException();
}

static void app_Startup(object sender, StartupEventArgs e)
{
throw new NotImplementedException();
}
}

如果通過(guò)XAML啟動(dòng)窗體的話,也會(huì)編譯成為為如下的程序,默認(rèn)路徑為Debug文件夾得App.g.cs文件:

public partial class App : System.Windows.Application {

///
///
InitializeComponent
///
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent() {

#line 4 "../../App.xaml"
this.StartupUri = new System.Uri("Window5.xaml", System.UriKind.Relative);

#line default
#line hidden
}

///
///
Application Entry Point.
///
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static void Main() {
WPFApplications.App app = new WPFApplications.App();
app.InitializeComponent();
app.Run();
}
}

    五、WPF應(yīng)用程序生存周期

image

    當(dāng)然這幅圖也只是簡(jiǎn)單的概括了WPF的執(zhí)行順序和生命周期,具體還要細(xì)致研究才是。

4.Window

    一、窗體類(lèi)基本概念

    對(duì)于WPF應(yīng)用程序,在Visual Studio和Expression Blend中,自定義的窗體均繼承System.Windows.Window類(lèi).大家都可能聽(tīng)說(shuō)過(guò)或者看過(guò)Applications = Code + Markup: A Guide to the Microsoft Windows Presentation Foundation這本書(shū),它里面就是用XAML和后臺(tái)代碼兩種形式來(lái)實(shí)現(xiàn)同一個(gè)功能,那么我們這里定義的窗體也由兩部分組成:

    1、 XAML文件,在這里面通常全部寫(xiě)UI的東西(希望大家還記得這兩幅圖)

   

7-4-2010 2-54-11 PM

7-4-2010 3-08-26 PM

2、后臺(tái)代碼文件

namespace WPFApplications
{
///
///
Interaction logic for Window5.xaml
///
public partial class Window5 : Window
{
public Window5()
{
InitializeComponent();
}

private void btnOK_Click(object sender, RoutedEventArgs e)
{
lblHello.Content = "Hello World Changed";
}
}
}

     也可以將后臺(tái)代碼放在XAML文件中,上面的例子可以改寫(xiě)為:

<Window x:Class="WPFApplications.Window5"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window5" Height="300" Width="300">
<
StackPanel>
<
Label x:Name="lblHello">Hello,World!Label>
<
Button x:Name="btnOK" Width="88" Height="22" Content="Click"
Click="btnOK_Click"/>
<
x:Code>
void btnOK_Click(object sender, System.Windows.RoutedEventArgs e)
{
lblHello.Content = "Hello World Changed";
}
]]>
x:Code>StackPanel>
Window>

     二、窗體的生命周期

1、顯示窗體

  • 構(gòu)造函數(shù)
  • Show()、ShowDialog()方法:Show()方法顯示非模態(tài)窗口,ShowDialog()方法顯示模態(tài)窗口,這個(gè)基本和WinForm類(lèi)似
  • Loaded事件:窗體第一次Show()或ShowDialog()時(shí)引發(fā)的事件,通常在此事件中加載窗體的初始化數(shù)據(jù),但如果用了MVVM模式,基本就不在這里面寫(xiě)。

2、關(guān)閉窗體

  • Close()方法:關(guān)閉窗體,并釋放窗體的資源
  • Closing事件、Closed事件:關(guān)閉時(shí)、關(guān)閉后引發(fā)的事件,通常在Closing事件中提示用戶(hù)是否退出等信息。

3、窗體的激活

  • Activate()方法:激活窗體
  • Activated、Deactivated事件:當(dāng)窗體激動(dòng)、失去焦點(diǎn)時(shí)引發(fā)的事件

4、窗體的生命周期

WindowLifeCycle

     為了證實(shí)上面的結(jié)論,我們用下面的代碼進(jìn)行測(cè)試:

public partial class Window3 : Window
{
public Window3()
{
this.Activated += new EventHandler(Window1_Activated);
this.Closing += new System.ComponentModel.CancelEventHandler(Window1_Closing);
this.ContentRendered += new EventHandler(Window1_ContentRendered);
this.Deactivated += new EventHandler(Window1_Deactivated);
this.Loaded += new RoutedEventHandler(Window1_Loaded);
this.Closed += new EventHandler(Window1_Closed);
this.Unloaded += new RoutedEventHandler(Window1_Unloaded);
this.SourceInitialized += new EventHandler(Window1_SourceInitialized);

InitializeComponent();
}


void Window1_Unloaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Unloaded");
}

void Window1_SourceInitialized(object sender, EventArgs e)
{
Debug.WriteLine("SourceInitialized");
}

void Window1_Loaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Loaded");
}

void Window1_Deactivated(object sender, EventArgs e)
{
Debug.WriteLine("Deactivated");
}

void Window1_ContentRendered(object sender, EventArgs e)
{
Debug.WriteLine("ContentRendered");
}

void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Debug.WriteLine("Closing");
MessageBoxResult dr = MessageBox.Show("Cancel the window?",
 "Answer", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (dr == MessageBoxResult.No)
{
e.Cancel = true;
}
}

void Window1_Closed(object sender, EventArgs e)
{
Debug.WriteLine("Closed");
}

void Window1_Activated(object sender, EventArgs e)
{
Debug.WriteLine("Activated");
}
}

執(zhí)行結(jié)果為:

image

    WPF窗體的詳細(xì)的屬性、方法、事件請(qǐng)參考MSDN,有很多的屬性、方法、事件與Windows應(yīng)用程序中 System.Windows.Forms.Form類(lèi)頗為相似,其中常用的一些屬性、方法、事件有:

  1. 窗體邊框模式(WindowStyle屬性)和是否允許更改窗體大?。≧esizeMode屬性) 。
  2. 窗體啟動(dòng)位置(WindowStartupLocation屬性)和啟動(dòng)狀態(tài)(WindowState屬性) 等。
  3. 窗體標(biāo)題(Title屬性)及圖標(biāo) 。
  4. 是否顯示在任務(wù)欄(ShowInTaskbar)
  5. 始終在最前(TopMost屬性)

5.Dispatcher及多線程

    提到這個(gè)UI和后臺(tái)線程交互這個(gè)問(wèn)題,大家都可能在WinForm中遇到過(guò),記得幾年前我參加一個(gè)外資企業(yè)的面試,公司的其中一道題就是說(shuō)在WinForm 中如何使用后臺(tái)線程來(lái)操作UI,所以對(duì)這個(gè)問(wèn)題比較記憶猶新。

    WPF線程分配系統(tǒng)提供一個(gè)Dispatcher屬性、VerifyAccess  和 CheckAccess 方法來(lái)操作線程。線程分配系統(tǒng)位于所有 WPF 類(lèi)中基類(lèi),大部分WPF 元素都派生于此類(lèi),如下圖的Dispatcher類(lèi):

image

    WPF 應(yīng)用程序啟動(dòng)后,會(huì)有兩個(gè)線程:

  1. 一個(gè)是用來(lái)處理UI呈現(xiàn)(處理UI的請(qǐng)求,比如輸入和展現(xiàn)等操作)。
  2. 一個(gè)用來(lái)管理 UI的 (對(duì)UI元素及整個(gè)UI進(jìn)行管理)。

    與 Dispatcher 調(diào)度對(duì)象想對(duì)應(yīng)的就是 DispatcherObject,在 WPF 中絕大部分控件都繼承自 DispatcherObject,甚至包括 Application。這些繼承自 DispatcherObject 的對(duì)象具有線程關(guān)聯(lián)特征,也就意味著只有創(chuàng)建這些對(duì)象實(shí)例,且包含了 Dispatcher 的線程(通常指默認(rèn) UI 線程)才能直接對(duì)其進(jìn)行更新操作。

    當(dāng)我們嘗試從一個(gè)非 UI 線程更新一個(gè)UI元素,會(huì)看到如下的異常錯(cuò)誤。

image

      XAML代碼

<Window x:Class="WPFApplications.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<
StackPanel>
<
Label x:Name="lblHello">Hello,World!Label>
StackPanel>
Window>

      后臺(tái)代碼

public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
Thread thread = new Thread(ModifyUI);
thread.Start();
}

private void ModifyUI()
{
// 模擬一些工作正在進(jìn)行
Thread.Sleep(TimeSpan.FromSeconds(5));
lblHello.Content = "Hello,Dispatcher";
}
}

錯(cuò)誤截圖:

image

    按照 DispatcherObject 的限制原則,我們改用 Window.Dispatcher.Invoke() 即可順利完成這個(gè)更新操作。

private void ModifyUINew()
{
// 模擬一些工作正在進(jìn)行
Thread.Sleep(TimeSpan.FromSeconds(5));
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,(ThreadStart)delegate()
{
lblHello.Content = "Hello,Dispatcher";
});
}

    如果在其他工程或者類(lèi)中,我們可以用 Application.Current.Dispatcher.Invoke方法來(lái)完成同樣的操作,它們都指向 UI Thread Dispatcher這個(gè)唯一的對(duì)象。

    Dispatcher 同時(shí)還支持 BeginInvoke 異步調(diào)用,如下代碼:

private void btnHello_Click(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(5));
this.lblHello.Content = DateTime.Now.ToString();
}));
}).Start();
}

    關(guān)于Dispatcher和WPF多線程,還有很多要講,由于篇幅有限且精力有限,我這里只講一些我們最常見(jiàn)的應(yīng)用,同時(shí)包括Freezable 的處理等問(wèn)題,大家可以查閱MSDN或者查閱國(guó)外相關(guān)的專(zhuān)題。

6.類(lèi)繼承結(jié)構(gòu)

    在WPF中常用的的控件類(lèi)繼承結(jié)構(gòu)如下圖所示(圖中圓圈的表示抽象類(lèi),方框的表示實(shí)體類(lèi)):

  • System.Object 類(lèi):大家都知道在.NET中所有類(lèi)型的根類(lèi)型,在圖中沒(méi)有畫(huà)出來(lái),DispatcherObject 就繼承于它,所以它是整個(gè)應(yīng)用系統(tǒng)的基類(lèi)。
  • System.Windows.Threading.DispatcherObject 類(lèi):WPF 中的絕大多數(shù)對(duì)象是從 DispatcherObject 派生的,它提供了用于處理并發(fā)和線程的基本構(gòu)造。WPF 是基于調(diào)度程序?qū)崿F(xiàn)的消息系統(tǒng)。
  • System.Windows.DependencyObject類(lèi):WPF基本所有的控件都實(shí)現(xiàn)了依賴(lài)屬性,它表示一個(gè)參與依賴(lài)項(xiàng)屬性系統(tǒng)的對(duì)象。
  • System.Windows.Media.Visual類(lèi):為 WPF 中的呈現(xiàn)提供支持,其中包括命中測(cè)試、坐標(biāo)轉(zhuǎn)換和邊界框計(jì)算等。
  • System.Windows.UIElement 類(lèi):UIElement 是 WPF 核心級(jí)實(shí)現(xiàn)的基類(lèi),該類(lèi)建立在 Windows Presentation Foundation (WPF) 元素和基本表示特征基礎(chǔ)上。
  • System.Windows.FrameworkElement類(lèi):為 Windows Presentation Foundation (WPF) 元素提供 WPF 框架級(jí)屬性集、事件集和方法集。此類(lèi)表示附帶的 WPF 框架級(jí)實(shí)現(xiàn),它是基于由UIElement定義的 WPF 核心級(jí) API 構(gòu)建的。
    • System.Windows.Controls.Control 類(lèi):表示 用戶(hù)界面 (UI) 元素的基類(lèi),這些元素使用 ControlTemplate 來(lái)定義其外觀。
      • System.Windows.Controls.ContentControl類(lèi):表示包含單項(xiàng)內(nèi)容的控件。
      • System.Windows.Controls.ItemsControl 類(lèi):表示一個(gè)可用于呈現(xiàn)項(xiàng)的集合的控件。

 


    • System.Windows.Controls.Panel類(lèi):為所有 Panel 元素(布局)提供基類(lèi)。使用 Panel 元素在 Windows Presentation Foundation (WPF) 應(yīng)用程序中放置和排列子對(duì)象。
    • System.Windows.Sharps.Sharp類(lèi):為 Ellipse、Polygon 和 Rectangle 之類(lèi)的形狀元素提供基類(lèi)。

除了上面的圖以外,還有幾個(gè)命名空間也很重要,如下:

  •  
    • System.Windows.Controls.Decorator 類(lèi):提供在單個(gè)子元素(如 Border 或 Viewbox)上或周?chē)?a href=/pingce/yingyong/ target=_blank class=infotextkey>應(yīng)用效果的元素的基類(lèi)。
    • System.Windows.Controls.Image 類(lèi):表示顯示圖像的控件。
    • System.Windows.Controls.MediaElement類(lèi):表示包含音頻和 /或視頻的控件。

7.WPF的邏輯樹(shù)和視覺(jué)樹(shù)

     關(guān)于這部分的內(nèi)容講起來(lái)就比較多了,正如上次大家的留言里說(shuō)的一樣,這個(gè)內(nèi)容如果拉開(kāi)來(lái)講肯定就要開(kāi)幾個(gè)篇幅,所以我們今天主要以講清楚概念為重點(diǎn),先看下面的一個(gè)XAML代碼的例子:

<Window x:Class="WPFApplications.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<
StackPanel>
<
Label>Hello,World!Label>
StackPanel>
Window>

    上面這個(gè)UI非常的簡(jiǎn)單,Window是一個(gè)根結(jié)點(diǎn),它有一個(gè)子結(jié)點(diǎn)StackPanel,StackPanel有一個(gè)子結(jié)點(diǎn)Label。注意Label下還有一個(gè)子結(jié)點(diǎn)string(LabelText),它同時(shí)也是一個(gè)葉子結(jié)點(diǎn)。這就構(gòu)成了窗口的一個(gè)邏輯樹(shù)。邏輯樹(shù)始終存在于WPF的UI中,不管UI是用XAML編寫(xiě)還是用代碼編寫(xiě)。WPF的每個(gè)方面(屬性、事件、資源等等)都是依賴(lài)于邏輯樹(shù)的。

    視覺(jué)樹(shù)基本上是邏輯樹(shù)的一種擴(kuò)展。邏輯樹(shù)的每個(gè)結(jié)點(diǎn)都被分解為它們的核心視覺(jué)組件。邏輯樹(shù)的結(jié)點(diǎn)對(duì)我們來(lái)說(shuō)是不可見(jiàn)的。而視覺(jué)樹(shù)不同,它暴露了視覺(jué)的實(shí)現(xiàn)細(xì)節(jié)。下面是Visual Tree結(jié)構(gòu)就表示了上面四行XAML代碼的視覺(jué)樹(shù)結(jié)構(gòu)(下面這幅圖片來(lái)源于WPF揭秘): 

    當(dāng)然并不是所有的邏輯樹(shù)結(jié)點(diǎn)都可以擴(kuò)展為視覺(jué)樹(shù)結(jié)點(diǎn)。只有從 System.Windows.Media.Visual或者System.Windows.Media.Visual3D繼承的元素才能被視覺(jué)樹(shù)所包含。其他的元素不能包含是因?yàn)樗鼈儽旧頉](méi)有自己的提交(Rendering)行為。在Windows Vista SDK Tools當(dāng)中的XamlPad提供查看Visual Tree的功能。需要注意的是XamlPad目前只能查看以Page為根元素,并且去掉了SizeToContent屬性的XAML文檔。如下圖所示:

    在visual studio的命令行中輸入xamlpad就可以進(jìn)入如下的界面:

7-13-2010 9-57-27 PM

SNAGHTML2cb4a61 
     通過(guò)上圖我們可以看到Visual Tree確實(shí)比較復(fù)雜,其中還包含有很多的不可見(jiàn)元素,比如ContentPresenter等。Visual Tree雖然復(fù)雜,但是在一般情況下,我們不需要過(guò)多地關(guān)注它。我們?cè)趶母旧细淖兛丶娘L(fēng)格、外觀時(shí),需要注意Visual Tree的使用,因?yàn)樵谶@種情況下我們通常會(huì)改變控件的視覺(jué)邏輯。 比如我們?cè)谧约簩?xiě)一些控件的時(shí)候,再比如我們對(duì)某些外觀進(jìn)行特別訂制的時(shí)候。
WPF 中還提供了遍歷邏輯樹(shù)和視覺(jué)樹(shù)的輔助類(lèi):System.Windows.LogicalTreeHelper和 System.Windows.Media.VisualTreeHelper。注意遍歷的位置,邏輯樹(shù)可以在類(lèi)的構(gòu)造函數(shù)中遍歷。但是,視覺(jué)樹(shù)必須在經(jīng)過(guò)至少一次的布局后才能形成。所以它不能在構(gòu)造函數(shù)遍歷。通常是在OnContentRendered進(jìn)行,這個(gè)函數(shù)為在布局發(fā)生后被調(diào)用。
     其實(shí)每個(gè)Tree結(jié)點(diǎn)元素本身也包含了遍歷的方法。比如,Visual類(lèi)包含了三個(gè)保護(hù)成員方法VisualParent、 VisualChildrenCount、GetVisualChild。通過(guò)它們可以訪問(wèn)Visual的父元素和子元素。而對(duì)于 FrameworkElement,它通常定義了一個(gè)公共的Parent屬性表示其邏輯父元素。特定的FrameworkElement子類(lèi)用不同的方式暴露了它的邏輯子元素。比如部分子元素是Children Collection,有是有時(shí)Content屬性,Content屬性強(qiáng)制元素只能有一個(gè)邏輯子元素。

     為了弄清楚這些概念,我們就通過(guò)如下代碼作為演示:

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
PrintLogicalTree(0, this);
}

protected override void OnContentRendered(EventArgs e)
{
base.OnContentRendered(e);
PrintVisualTree(0, this);
}

void PrintLogicalTree(int depth, object obj)
{
// 打印空格,方便查看
Debug.WriteLine(new string(' ', depth) + obj);

// 如果不是DependencyObject,如string等類(lèi)型
if (!(obj is DependencyObject)) return;

// 遞歸打印邏輯樹(shù)
foreach (object child in LogicalTreeHelper.GetChildren(
obj as DependencyObject))
{
PrintLogicalTree(depth + 1, child);
}
}

void PrintVisualTree(int depth, DependencyObject obj)
{
//打印空格,方便查看
Debug.WriteLine(new string(' ', depth) + obj);

// 遞歸打印視覺(jué)樹(shù)
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
PrintVisualTree(depth + 1, VisualTreeHelper.GetChild(obj, i));
}
}
}

     結(jié)果為:

image

8.本文總結(jié)

     本篇主要對(duì)Application、window、多線程、類(lèi)繼承結(jié)構(gòu)、邏輯樹(shù)與可視樹(shù)等的理論和實(shí)際Demo進(jìn)行了探討,通過(guò)這一篇文章,我們可以大概了解WPF在這些元素上的處理,同時(shí)也給我后面的內(nèi)容奠定了基礎(chǔ),后面會(huì)逐漸牽涉到實(shí)際的一些案例和新的概念,所以如果有不熟悉且對(duì)這個(gè)專(zhuān)題感興趣的朋友可以仔細(xì)看一下這篇文章,在文章后面也會(huì)把本文用到的代碼附加上去,大家可以下載下來(lái)進(jìn)行測(cè)試。

     最后圣殿騎士 會(huì)盡心盡力寫(xiě)好這個(gè)系列,同時(shí)由于是自己對(duì)這些技術(shù)的使用總結(jié)和心得體會(huì),錯(cuò)誤之處在所難免,懷著技術(shù)交流的心態(tài),在博客園51CTO發(fā)表出來(lái),所以希望大家能夠多多指點(diǎn),這樣在使一部分人受益的同時(shí)也能糾正我的錯(cuò)誤觀點(diǎn),以便和各位共同提高,后續(xù)文章敬請(qǐng)關(guān)注!

9.系列進(jìn)度(紅色標(biāo)示已發(fā)布)

· 1. WPF 基礎(chǔ)到企業(yè)應(yīng)用系列1——開(kāi)篇有益

· 2. WPF 基礎(chǔ)到企業(yè)應(yīng)用系列2——WPF前世今生

· 3. WPF 基礎(chǔ)到企業(yè)應(yīng)用系列3——WPF開(kāi)發(fā)漫談

· 4. WPF 基礎(chǔ)到企業(yè)應(yīng)用系列4——WPF千年輪回

· 5. 使用面板做布局(幾種布局控件的XAML及CS代碼,綜合布局等)

· 6. 依賴(lài)屬性、附加屬性(基本、繼承、元數(shù)據(jù))

· 7. 路由事件、附加事件

· 8. 命令

· 9. WPF控件分類(lèi)介紹與使用技巧(ContentControl、HeaderedContentControl…… Decorator)

· 10. 尺寸縮放、定位與變換元素

· 11. 資源

· 12. 數(shù)據(jù)綁定(基本、值轉(zhuǎn)換、驗(yàn)證、集合的篩選、排序、分組、主從、數(shù)據(jù)提供者)

· 13. 樣式

· 14. 模板

· 15. 多語(yǔ)言、皮膚和主題

· 16. 2D圖形

· 17. 3D圖形

· 18. 動(dòng)畫(huà)(幾種動(dòng)畫(huà)的應(yīng)用

· 19. 音頻、視頻、語(yǔ)音

· 20. 文檔、打印、報(bào)表

· 21. 用戶(hù)控件和自定義控件

· 22. Win32、Windows Form以及ActiveX之間的互用性

· 23. 構(gòu)建并部署應(yīng)用程序(ClickOnce部署、微軟setup /InstallShield+自動(dòng)更新組件)

· 24. WPF的模式講解及實(shí)例(MVC Demo)

· 25. WPF的模式講解及實(shí)例(MVP Demo)

· 26. WPF的模式講解及實(shí)例(MVVM Demo)

· 27. 性能優(yōu)化(WPF項(xiàng)目的瓶頸)

· 28.一個(gè)完整WPF項(xiàng)目(普通架構(gòu)版)

· 39. 一個(gè)完整WPF項(xiàng)目(MVVM架構(gòu)版)

· 30. WPF 4.0新功能

NET技術(shù)WPF 基礎(chǔ)到企業(yè)應(yīng)用系列4——WPF千年輪回,轉(zhuǎn)載需保留來(lái)源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 婷婷色综合久久 | 91大神精品长腿在线观看网站 | 色狠狠一区二区三区香蕉蜜桃 | 成人在线免费 | 午夜视频福利在线观看 | 四虎国产精品免费视 | 国产自制一区 | 午夜噜噜 | 色婷婷综合欧美成人 | 四虎影永久在线观看网址 | 韩国美女一级片 | 亚洲综合一区二区 | 五月婷婷 六月丁香 | 久草一级片| 成人福利免费在线观看 | 久久久久亚洲香蕉网 | 视色4se网站在线 | 日本伊人色综合网站 | 国产农村乱子伦精品视频 | 最新91视频 | 国产在线视频网 | 91精品视频观看 | 国产成人激情视频 | 亚洲a视频 | 999热精品这里在线观看 | 精品在线视频免费 | 国产在线一区二区视频 | 怡红院成人网 | 91嫩草视频在线观看 | 看全大色黄大色黄大片一级爽 | 2021国产精品自产拍在线 | 午夜精品免费 | 全部免费69堂在线视频 | 国产一区二区三区免费播放 | 91国在线| 久久综合久久久 | 在线精品免费视频 | 热伊人99re久久精品最新地 | 久久久久久久久女黄9999 | 护士精品一区二区三区 | 亚洲春色另类小说 |