日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Silverlight 2 Customized Control 开发

發布時間:2025/1/21 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Silverlight 2 Customized Control 开发 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Customized Control 和 User Control

相信大家比較熟悉使用Silverlight的User Control,在VS2008的Silverlight插件中,可以通過添加新項(Add new Item)創建一個User Control,而且Silverlight在網頁中嵌入的本身就是一個User Control。

本文中講的是如何開發Customized Control,Customized Control是與User Control完全不同的,Customized Control是繼承或者間接繼承System.Windows.Controls.Control的,而User Control必須繼承System.Windows.Controls.Control.UserControl。Customized Control更接近于Silverlight本身提供的Button、CheckBox等Control, User Control則比較類似這些原生Control的組合體。

準備工作

在閱讀本文之前至少應該掌握:

  • 創建和使用簡單Silverlight程序
  • 使用和編輯Silverlight控件模板
  • 使用Silverlight的Visual State
  • C#基本知識
  • 使用Visual studio的項目和解決方案

推薦鏈接

  • http://msdn.microsoft.com/zh-cn/magazine/cc721611.aspx?
    一篇for SL2 beta 2的自定義控件開發介紹,有些地方需要變動才能正常工作
  • http://silverlight.net/GetStarted/?
    官方的Silverlight入門, 其中有SL組成員blog的鏈接
  • http://msdn.microsoft.com/en-us/library/cc278068(VS.95).aspx?
    MSDN的Control Customization介紹
  • http://msdn.microsoft.com/en-us/library/cc838194(VS.95).aspx?
    MSDN的Silverlight類庫參考

環境

  • Visual Studio 2008 with Service Pack 1
  • Silverlight Tools for Visual Studio 2008 SP1
  • [optional]Expression Blend 2 with Service Pack 1

(提示:連接給出的默認是英文,大家可以根據習慣選擇。開發工具和Service Pack語言必須對應。)

(注意:Visual Studio和Expression Blend不是免費工具,這里給出的是試用版本鏈接,用于商業開發可能存在風險。)

?

接下來我們可以開始Customized Control之旅了。

(因為不想在基礎的地方浪費時間,所以前面部分會非常簡略,請參考推薦鏈接)

?

一、創建解決方案

Customized Control一般會編寫成DLL文件,所以創建工程的時候應該選擇Silverlight Class Library,同時為了調試,我們還要在解決方案中再建立一個新的Silverlight Application project。如果希望用Web站點來調試Silverlight Application,就還需要創建解決方案中的第三個project,推薦使用動態生成的HTML。然后需要在解決放案屬性中定義好項目的依賴關系以及start up project。考慮到這部分大家都比較了解,就不再贅述。

二、創建Control的C#類

創建的Silverlight Class Library中默認會有一個Class1.cs,這是一個普通的C#類,與Silverlight并無關系,可以選擇保留它利用VS的重構功能換成喜歡的名字,也可以刪掉它再重新建立一個類。總之我們的Class Library中只需要保留一個我們要開發的控件名字的類就可以了,比如我打算開發一個MenuItem。然后我們要繼承Control類,當然也可以繼承任何其它繼承了Control的類。最后代碼看起來像是這樣:

????public?class?MenuItem?:?Control
????{
????????
public?MenuItem()
????????{
????????}
????}

?

OK,這樣我們就制作出了一個最基本的Customized Control。

三、調用Control

接下來我們希望在Silverlight Application中調用生成的Customized Control,首先要添加引用,因為現在在同一Solution中,所以可以選擇項目引用。

然后我們要把我們類庫的clr命名空間加入到XAML的命名空間當中,所以修改Page.xaml的UserControl為:

?

<UserControl?x:Class="SilverlightMenuTest.Page"
????xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
????xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
????xmlns:custom
="clr-namespace:SilverlightMenu;assembly=SilverlightMenu"
????Width
="400"?Height="300"?/>

?

?

clr-namespace寫我們類庫中使用的namespace,assembly寫類庫項目的名稱就可以了,XML命名空間可以是我們喜歡的任何名字,這里用了custom。

然后我們可以在XAML中使用我們的新控件了,控件名稱和C#類名相同,前面要帶上命名空間,代碼最后類似這樣:

<UserControl?x:Class="SilverlightMenuTest.Page"
????xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
????xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
????xmlns:custom
="clr-namespace:SilverlightMenu;assembly=SilverlightMenu"
????Width
="400"?Height="300">
????
<Grid?x:Name="LayoutRoot"?Background="White">
????????
<custom:MenuItem?/>
????
</Grid>
</UserControl>

接下來我們可以運行程序了,但是當然結果是一片空白。

四、添加模板

這個一片空白的Control顯然沒有任何意義,接下來我們要讓它變成可見的。只需要設置好MenuItem的Template屬性就可以了,可以看到這里設置了Width和Height,Template中的元素會自動把自己限制在這個范圍內。

<UserControl?x:Class="SilverlightMenuTest.Page"
????xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
????xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
????xmlns:custom
="clr-namespace:SilverlightMenu;assembly=SilverlightMenu"
????Width
="400"?Height="300">
????
<Grid?x:Name="LayoutRoot"?Background="White"?Width="100"?Height="24">
????????
<custom:MenuItem>
????????????
<custom:MenuItem.Template>
????????????????
<ControlTemplate>
????????????????????
<Rectangle?Fill="Black"?StrokeThickness="1"?RadiusX="2"?RadiusY="2"?x:Name="Bg"/>
????????????????
</ControlTemplate>
????????????
</custom:MenuItem.Template>
????????
</custom:MenuItem>
????
</Grid>
</UserControl> 顯示這段代碼我們就可以看到一個黑色的圓角矩形了。

五、綁定屬性

這樣我們有了一個可見的控件,但是這個控件的任何屬性(如Background之類的)都沒有辦法發生作用。現在我們可以想想辦法讓矩形的顏色是控件的背景色。使用Silverlight的屬性文法,可以將矩形的Fill屬性綁定到MenuItem控件的Background。

<UserControl?x:Class="SilverlightMenuTest.Page"
????xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
????xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
????xmlns:custom
="clr-namespace:SilverlightMenu;assembly=SilverlightMenu"
????Width
="400"?Height="300">
????
<Grid?x:Name="LayoutRoot"?Background="White"?Width="100"?Height="24">
????????
<custom:MenuItem?Background="Blue"?>
????????????
<custom:MenuItem.Template>
????????????????
<ControlTemplate>
????????????????????
<Rectangle?Fill="{TemplateBinding?Background}"?StrokeThickness="1"?RadiusX="2"?RadiusY="2"?x:Name="Bg"/>
????????????????
</ControlTemplate>
????????????
</custom:MenuItem.Template>
????????
</custom:MenuItem>
????
</Grid>
</UserControl>

感興趣的話,可以試著把Rectangle的Stroke綁定到MenuItem的BorderBrush。這樣,我們就可以通過控件的屬性控制控件的顯示效果了。

六、添加默認模板

當然你不能要求使用者總是編輯你的Control的模板,所以我們必須要有一個默認的模板。VisualStudio總是會從項目的themes文件夾下查找generic.xaml作為默認模板,注意這個項目是控件的類所在的項目,也就是我們建立的Silverlight Class Library。

如果你看過之前的介紹Silverlight自定義控件開發的文章,你會發現,這個地方Silverlight 2 RTW版和Silverlight 2 beta 2或者beta 1是不兼容的,我們必須將generic.xaml放到themes目錄下。beta 2版本是放在根目錄下,而beta 1版本是放在根目錄下且必須修改generic.xaml的屬性才能生效。

一個空的generic.xaml的內容如下(但是VS不會自動為你生成這個文件,需要手動添加):

<ResourceDictionary
????
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
????xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml">
</ResourceDictionary>

我們需要通過style把新控件的模板放進去,但之前應該先把clr命名空間加入。

<ResourceDictionary
????
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
????xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
????xmlns:custom
="clr-namespace:SilverlightMenu;assembly=SilverlightMenu">
</ResourceDictionary>

最后的XAML類似這樣(style大家并不陌生,就不多講了)

?

<ResourceDictionary
????
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
????xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
????xmlns:custom
="clr-namespace:SilverlightMenu;assembly=SilverlightMenu">
????
<Style?TargetType="custom:MenuItem">
????????
<Setter?Property="Template">
????????????
<Setter.Value>
????????????????
<ControlTemplate?TargetType="custom:MenuItem">
????????????????????
<Rectangle?Fill="{TemplateBinding?Background}"?StrokeThickness="1"?RadiusX="2"?RadiusY="2"?x:Name="Bg"/>
????????????????
</ControlTemplate>
????????????
</Setter.Value>
????????
</Setter>
????
</Style>
</ResourceDictionary>

?

但僅僅如此控件是不會有任何變化的,要在MenuItem的構造函數中加入一句:

this.DefaultStyleKey?=?typeof(MenuItem); 這樣我們的Control就更接近原生Control了,可以這樣調用: <UserControl?x:Class="SilverlightMenuTest.Page"
????xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
????xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
????xmlns:custom
="clr-namespace:SilverlightMenu;assembly=SilverlightMenu"
????Width
="400"?Height="300">
????
<Grid?x:Name="LayoutRoot"?Background="White"?Width="100"?Height="24">
????????
<custom:MenuItem?Background="Black"></custom:MenuItem>
????
</Grid>
</UserControl>

再運行就可以看到黑色矩形了。

七、綁定事件

到此為止,我們的Control還只能是顯示出來看看,沒有任何交互性,下面我們就來給它添加一定的交互性。因為Control本身提供了一些事件,所以我們很容易捕獲這些事件并作出響應。對于Control來說,我們只需要添加事件處理函數并且綁定到相應事件就可以了。

namespace?System.Windows.Controls
{
????
public?class?MenuItem?:?Control
????{
????????
public?MenuItem()
????????{
????????????
this.DefaultStyleKey?=?typeof(MenuItem);
????????????
this.MouseEnter?+=?new?MouseEventHandler(OnMouseEnter);
????????}
????????
public?void?OnMouseEnter(object?sender,?MouseEventArgs?args)
????????{
????????}
????}
}
可以在OnMouseEnter中設置斷點來觀察事件響應情況。

八、操作模板成員

現在我們知道了如何通過事件處理函數響應事件,我們可以在其中改變控件自身的狀態,比如,當鼠標劃過時,改變控件的背景。前面說到背景顯示是通過一個Rectangle實現的,那么要改變背景就需要取到這個Rectangle,我們要使用一個函數GetTemplateChild來取這個元素。注意因為GetTemplateChild并不一定總能取到元素,而且元素類型并不一定是我們期望的(了解Template的朋友會知道,Template是一個可以被EndUser修改的屬性,所以不能以任何形式斷言控件Template的結構和其中的元素名),所以一定要處理異常。下面的代碼是讓鼠標在控件上時背景變成紅色:

public?class?MenuItem?:?Control
{
????
public?MenuItem()
????
{
????????
this.DefaultStyleKey?=?typeof(MenuItem);
????????
this.MouseEnter?+=?new?MouseEventHandler(OnMouseEnter);
????????
this.MouseLeave?+=?new?MouseEventHandler(OnMouseLeave);
????}

????
public?void?OnMouseEnter(object?sender,?MouseEventArgs?args)
????
{
????????
try
????????
{
????????????Rectangle?BgRect?
=?GetTemplateChild("Bg")?as?Rectangle;
????????????BgRect.Fill?
=?new?SolidColorBrush(Color.FromArgb(255,?255,?0,?0));
????????}

????????
catch
????????
{
????????}

????}

????
public?void?OnMouseLeave(object?sender,?MouseEventArgs?args)
????
{
????????
try
????????
{
????????????Rectangle?BgRect?
=?GetTemplateChild("Bg")?as?Rectangle;
????????????BgRect.Fill?
=?new?SolidColorBrush(Color.FromArgb(255,?0,?0,?0));
????????}

????????
catch
????????
{
????????}

????}

}
有些時候,我們希望在模板生效的時候就對某些模板成員進行操作,如綁定事件,調整屬性等,就需要一個事件OnApplyTemplate,我們只能通過override父類的OnApplyTemplate來響應模板生效事件:

?

九、添加可視狀態(VisualState)

上面的代碼實現了我們想要的功能,然而卻有很多問題:

  • 顏色是硬編碼
  • 無法保留設置的背景色(只能是黑色)
  • 顯示樣式用C#代碼書寫,不符合XAML+C#界面和邏輯分開的精神
  • 那么如何解決呢?很顯然,跟使用Silverlight開發Web應用一樣,答案就是使用VisualState。首先我們要為我們的控件模板定義VisualState,因為VisualState必須定義在root element上,所以這里我稍微做了一點改動,給模板加了一個容器。關于如何定義和使用VisualState,早有不少高手寫的很清楚,這里就不再重復了。下面的Visual定義了2個互斥的狀態MouseOver和MouseOut,MouseOver狀態將背景Rectangle顏色變紅,MouseOut則恢復原狀。

    <ResourceDictionary
    ????
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    ????xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"
    ????xmlns:vsm
    ="clr-namespace:System.Windows;assembly=System.Windows"
    ????xmlns:custom
    ="clr-namespace:System.Windows.Controls;assembly=SilverlightMenu">
    ????
    <Style?TargetType="custom:MenuItem">
    ????????
    <Setter?Property="Template">
    ????????????
    <Setter.Value>
    ????????????????
    <ControlTemplate?TargetType="custom:MenuItem">
    ????????????????????
    <Grid>
    ????????????????????????
    <vsm:VisualStateManager.VisualStateGroups>
    ????????????????????????????
    <vsm:VisualStateGroup?x:Name="MouseOverStates">
    ????????????????????????????????
    <vsm:VisualState?x:Name="MouseOver">
    ????????????????????????????????????
    <Storyboard>
    ????????????????????????????????????????
    <ObjectAnimationUsingKeyFrames?Storyboard.TargetName="Bg"?Storyboard.TargetProperty="Fill"?Duration="0:0:0">
    ????????????????????????????????????????????
    <ObjectAnimationUsingKeyFrames.KeyFrames>
    ????????????????????????????????????????????????
    <DiscreteObjectKeyFrame?KeyTime="0:0:0">
    ????????????????????????????????????????????????????
    <DiscreteObjectKeyFrame.Value>
    ????????????????????????????????????????????????????????
    <SolidColorBrush?Color="#FFFF0000"></SolidColorBrush>
    ????????????????????????????????????????????????????
    </DiscreteObjectKeyFrame.Value>
    ????????????????????????????????????????????????
    </DiscreteObjectKeyFrame>
    ????????????????????????????????????????????
    </ObjectAnimationUsingKeyFrames.KeyFrames>
    ????????????????????????????????????????
    </ObjectAnimationUsingKeyFrames>
    ????????????????????????????????????
    </Storyboard>
    ????????????????????????????????
    </vsm:VisualState>
    ????????????????????????????????
    <vsm:VisualState?x:Name="MouseOut">
    ????????????????????????????????????
    <Storyboard>
    ????????????????????????????????????
    </Storyboard>
    ????????????????????????????????
    </vsm:VisualState>
    ????????????????????????????
    </vsm:VisualStateGroup>
    ????????????????????????
    </vsm:VisualStateManager.VisualStateGroups>
    ????????????????????????
    <Rectangle?Fill="{TemplateBinding?Background}"?StrokeThickness="1"?RadiusX="2"?RadiusY="2"?x:Name="Bg"/>
    ????????????????????
    </Grid>
    ????????????????
    </ControlTemplate>
    ????????????
    </Setter.Value>
    ????????
    </Setter>
    ????
    </Style>
    </ResourceDictionary>

    定義好了Visual State,我們的事件就可以寫的很簡單了:

    public?class?MenuItem?:?Control
    {
    ????
    public?MenuItem()
    ????{
    ????????
    this.DefaultStyleKey?=?typeof(MenuItem);
    ????????
    this.MouseEnter?+=?new?MouseEventHandler(OnMouseEnter);
    ????????
    this.MouseLeave?+=?new?MouseEventHandler(OnMouseLeave);
    ????}
    ????
    public?void?OnMouseEnter(object?sender,?MouseEventArgs?args)
    ????{
    ????????VisualStateManager.GoToState(
    this,?"MouseOver",?false);
    ????}
    ????
    public?void?OnMouseLeave(object?sender,?MouseEventArgs?args)
    ????{
    ????????VisualStateManager.GoToState(
    this,?"MouseOut",?false);
    ????}
    }
    這樣運行下試試看,是不是很cool?

    ?

    十、添加自定義屬性

    接下來到了最后的部分了,也是最少資料涉及的部分,Silverlight Customized Control自定義屬性。下面我們來以一個Text屬性為例演示如何創建一個自定義屬性,這個例子將會用到一些前面的內容。首先我們要為DependencyObject的屬性聲明一個公有的DependencyProperty,這個屬性是靜態的,可以用于數據綁定。(還記得數據綁定中使用的DependencyProperty吧,就是這樣的哦^^)

    ?

    ????public?static?readonly?DependencyProperty?TextProperty;

    ?

    靜態屬性在靜態構造函數中初始化,這里有一點復雜,首先看完整代碼:

    ????static?MenuItem()
    ????{
    ????????TextProperty?
    =?DependencyProperty.Register("Text",?typeof(string),?typeof(MenuItem),?new?PropertyMetadata(false,?new?PropertyChangedCallback(MenuItem.OnTextPropertyChanged)));
    ????}
    DependencyProperty應該由DependencyProperty.Register創建,在MSDN中,這個函數的原型如下: public?static?DependencyProperty?Register(
    ????
    string?name,
    ????Type?propertyType,
    ????Type?ownerType,
    ????PropertyMetadata?typeMetadata
    )
    ?

    其中name是屬性在XAML中使用的名字,propertyType則是屬性的類型,注意這個屬性理論上可以是任何類型,但是一般只使用整數、布爾、字符串、還有UI元素這些類型,其它類型需要定義復雜的字符串到對象的屬性文法作為轉換規則(之后可能會單寫一篇blog講converter)。ownerType就是我們自己定義的類了。typeMetadata有點復雜,PropertyMetadata構造函數有3個重載,提供選擇指定defaultValue和propertyChangedCallback中任意一個或者同時指定2個。原型如下:

    public?PropertyMetadata(
    ????Object?defaultValue,
    ????PropertyChangedCallback?propertyChangedCallback
    )

    ?

    defaultValue是屬性的默認值沒什么可說,propertyChangedCallback也很簡單,就是當屬性改變時的處理函數,這個是把屬性同我們的類聯系起來的關鍵了,PropertyChangedCallback 是個委托類型,它的簽名也可以在MSDN查到:

    public?delegate?void?PropertyChangedCallback(
    ????DependencyObject?d,
    ????DependencyPropertyChangedEventArgs?e
    )

    為了理解這個函數,我們可以先看一下我對Text屬性的實現:

    ????private?static?void?OnTextPropertyChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e)
    ????{
    ????????(d?
    as?MenuItem).OnTextPropertyChanged(e);
    ????}
    ????
    void?OnTextPropertyChanged(DependencyPropertyChangedEventArgs?e)
    ????{
    ????????
    try
    ????????{
    ????????????(GetTemplateChild(
    "TB")?as?TextBlock).Text?=?e.NewValue?as?string;
    ????????}
    ????????
    catch
    ????????{
    ????????}
    ????}
    其實可以在static的OnTextPropertyChanged里面直接操作也是可以的,這個實現結構比較合理。可以看到,這個PropertyChangedCallback參數中,d就是屬性所在的對象,而e則是屬性改變時的信息,包括NewValue,OldValue等等,通常我們關心的是NewValue。

    之后,我們要給我們的對象添加一個相應的C#屬性,這個屬性一定要和XAML里的屬性名字完全一致,因為DependencyObject會用反射來訪問這個屬性。這個屬性的getter和setter中不應該有多余的內容,應該只是簡單的轉發操作到DependencyObject,所以看起來就像下面這樣:???????

    ????public?string?Text
    ????{
    ????????
    get
    ????????{
    ????????????
    return?(string)base.GetValue(TextProperty);
    ????????}
    ????????
    set
    ????????{
    ????????????
    base.SetValue(TextProperty,?value);
    ????????}
    ????}
    然后我們還需要設置模板內容,把TextBlock加入。generic.xaml最終版如下:

    ?

    <ResourceDictionary????
    ????
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"????
    ????xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"????
    ????xmlns:vsm
    ="clr-namespace:System.Windows;assembly=System.Windows"????
    ????xmlns:custom
    ="clr-namespace:System.Windows.Controls;assembly=SilverlightMenu">
    ????
    <Style?TargetType="custom:MenuItem">
    ????????
    <Setter?Property="Template">
    ????????????
    <Setter.Value>
    ????????????????
    <ControlTemplate?TargetType="custom:MenuItem">
    ????????????????????
    <Grid>
    ????????????????????????
    <vsm:VisualStateManager.VisualStateGroups>
    ????????????????????????????
    <vsm:VisualStateGroup?x:Name="MouseOverStates">
    ????????????????????????????????
    <vsm:VisualState?x:Name="MouseOver">
    ????????????????????????????????????
    <Storyboard>
    ????????????????????????????????????????
    <ObjectAnimationUsingKeyFrames?Storyboard.TargetName="Bg"?Storyboard.TargetProperty="Fill"?Duration="0:0:0">
    ????????????????????????????????????????????
    <ObjectAnimationUsingKeyFrames.KeyFrames>
    ????????????????????????????????????????????????
    <DiscreteObjectKeyFrame?KeyTime="0:0:0">
    ????????????????????????????????????????????????????
    <DiscreteObjectKeyFrame.Value>
    ????????????????????????????????????????????????????????
    <SolidColorBrush?Color="#FFFF0000"></SolidColorBrush>
    ????????????????????????????????????????????????????
    </DiscreteObjectKeyFrame.Value>
    ????????????????????????????????????????????????
    </DiscreteObjectKeyFrame>
    ????????????????????????????????????????????
    </ObjectAnimationUsingKeyFrames.KeyFrames>
    ????????????????????????????????????????
    </ObjectAnimationUsingKeyFrames>
    ????????????????????????????????????
    </Storyboard>
    ????????????????????????????????
    </vsm:VisualState>
    ????????????????????????????????
    <vsm:VisualState?x:Name="MouseOut">
    ????????????????????????????????????
    <Storyboard></Storyboard>
    ????????????????????????????????
    </vsm:VisualState>
    ????????????????????????????
    </vsm:VisualStateGroup>
    ????????????????????????
    </vsm:VisualStateManager.VisualStateGroups>
    ????????????????????????
    <Rectangle?Fill="{TemplateBinding?Background}"?StrokeThickness="1"?RadiusX="2"?RadiusY="2"?x:Name="Bg"/>
    ????????????????????????
    <TextBlock?x:Name="TB"></TextBlock>
    ????????????????????
    </Grid>
    ????????????????
    </ControlTemplate>
    ????????????
    </Setter.Value>
    ????????
    </Setter>
    ????
    </Style>
    </ResourceDictionary>?

    這樣看起來就基本完成了,然而,在測試代碼里加入這個屬性之后,卻得不到我們想要的結果。

    <UserControl?x:Class="SilverlightMenuTest.Page"????
    ????xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"????
    ????xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml"????
    ????xmlns:custom
    ="clr-namespace:System.Windows.Controls;assembly=SilverlightMenu"????
    ????Width
    ="400"?Height="300">
    ????
    <Grid?x:Name="LayoutRoot"?Background="White"?Width="400"?Height="300">
    ????????
    <custom:MenuItem?Text="Hello"?Background="Black"?Width="100"?Height="24"></custom:MenuItem>
    ????
    </Grid>
    </UserControl>

    為什么呢,注意到,我們在屬性變化的時候直接GetTemplateChild,并沒有考慮到這時TextBlock是否已經創建,在SL中,Text屬性設置其實是發生在Template生效之前的,所以設置Text的時候取不到TB元素。那么,我們就需要考慮在加載模板完成的時候,取出Text屬性并且設置到TB上。

    如上文所述,我們override OnApplyTemplate來獲取想要的結果,最終版的MenuItem.cs代碼:

    ?

    using?System;
    using?System.Net;
    using?System.Windows;
    using?System.Windows.Controls;
    using?System.Windows.Documents;
    using?System.Windows.Ink;
    using?System.Windows.Input;
    using?System.Windows.Media;
    using?System.Windows.Media.Animation;
    using?System.Windows.Shapes;
    using?System.ComponentModel;
    namespace?System.Windows.Controls
    {
    ????
    public?class?MenuItem?:?Control
    ????
    {
    ????????
    public?static?readonly?DependencyProperty?TextProperty;
    ????????
    static?MenuItem()
    ????????
    {
    ????????????TextProperty?
    =?DependencyProperty.Register("Text",?typeof(string),?typeof(MenuItem),?new?PropertyMetadata("",?new?PropertyChangedCallback(MenuItem.OnTextPropertyChanged)));
    ????????}

    ????????
    private?static?void?OnTextPropertyChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e)
    ????????
    {
    ????????????(d?
    as?MenuItem).OnTextPropertyChanged(e);
    ????????}

    ????????
    void?OnTextPropertyChanged(DependencyPropertyChangedEventArgs?e)
    ????????
    {
    ????????????
    try
    ????????????
    {
    ????????????????(GetTemplateChild(
    "TB")?as?TextBlock).Text?=?e.NewValue?as?string;
    ????????????}

    ????????????
    catch
    ????????????
    {?}
    ????????}

    ????????
    public?string?Text
    ????????
    {
    ????????????
    get
    ????????????
    {
    ????????????????
    return?(string)base.GetValue(TextProperty);
    ????????????}

    ????????????
    set
    ????????????
    {
    ????????????????
    base.SetValue(TextProperty,?value);
    ????????????}

    ????????}

    ????????
    public?MenuItem()
    ????????
    {
    ????????????
    this.DefaultStyleKey?=?typeof(MenuItem);
    ????????????
    this.MouseEnter?+=?new?MouseEventHandler(OnMouseEnter);
    ????????????
    this.MouseLeave?+=?new?MouseEventHandler(OnMouseLeave);
    ????????}

    ????????
    public?override?void?OnApplyTemplate()
    ????????
    {
    ????????????
    base.OnApplyTemplate();
    ????????????
    try
    ????????????
    {
    ????????????????var?tb?
    =?GetTemplateChild("TB")?as?TextBlock;
    ????????????????(GetTemplateChild(
    "TB")?as?TextBlock).Text?=?this.Text;
    ????????????}

    ????????????
    catch
    ????????????
    {?}
    ????????}

    ????????
    public?void?OnMouseEnter(object?sender,?MouseEventArgs?args)
    ????????
    {
    ????????????VisualStateManager.GoToState(
    this,?"MouseOver",?false);
    ????????}

    ????????
    public?void?OnMouseLeave(object?sender,?MouseEventArgs?args)
    ????????
    {
    ????????????VisualStateManager.GoToState(
    this,?"MouseOut",?false);
    ????????}

    ????}

    }


    寫到這里,我們的自定義Control開發大體流程以及關鍵技術問題就已經比較清楚了,雖然這個MenuItem距離實用還有很遠的距離,各位應該可以自己完成它。感謝讀完本文的你,Enjoy Silverlight Customized Control.

    總結

    以上是生活随笔為你收集整理的Silverlight 2 Customized Control 开发的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。