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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[UWP]依赖属性2:使用依赖属性

發(fā)布時(shí)間:2023/12/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [UWP]依赖属性2:使用依赖属性 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原文:[UWP]依賴屬性2:使用依賴屬性

5. 完整的自定義依賴屬性

5.1 定義

/// <summary> /// 標(biāo)識 Title 依賴屬性。 /// </summary> public static readonly DependencyProperty TitleProperty =DependencyProperty.Register("Title", typeof(string), typeof(MyPage), new PropertyMetadata(string.Empty));/// <summary> /// 獲取或設(shè)置Content的值 /// </summary> public object Content {get { return (object)GetValue(ContentProperty); }set { SetValue(ContentProperty, value); } }/// <summary> /// 標(biāo)識 Content 依賴屬性。 /// </summary> public static readonly DependencyProperty ContentProperty =DependencyProperty.Register("Content", typeof(object), typeof(MyPage), new PropertyMetadata(null, OnContentChanged));private static void OnContentChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) {MyPage target = obj as MyPage;object oldValue = (object)args.OldValue;object newValue = (object)args.NewValue;if (oldValue != newValue)target.OnContentChanged(oldValue, newValue); }protected virtual void OnContentChanged(object oldValue, object newValue) { }

以上代碼為一個(gè)相對完成的依賴屬性例子(還有一些功能比較少用就不寫出了),從這段代碼可以看出,自定義依賴屬性的步驟如下:

  • 注冊依賴屬性并生成依賴屬性標(biāo)識符。依賴屬性標(biāo)識符為一個(gè)public static readonly DependencyProperty字段,在上面這個(gè)例子中,依賴屬性標(biāo)識符為ContentProperty。依賴屬性標(biāo)識符的名稱必須為“屬性名+Property”。在PropertyMetadata中指定屬性默認(rèn)值。

  • 實(shí)現(xiàn)屬性包裝器。為屬性提供 CLR get 和 set 訪問器,在Getter和Setter中分別調(diào)用GetValue和SetValue。Getter和Setter中不應(yīng)該有其它任何自定義代碼。

    注意: Setter中不要寫其它任何自定義代碼這點(diǎn)很重要,如果使用Binding或其它XAML中賦值的方式,程序并不會(huì)使用Setter,而是直接調(diào)用SetValue函數(shù)賦值。這也是為什么需要使用一個(gè)PropertyChangedCallback統(tǒng)一處理所有值變更事件,而不是直接寫在Setter里面。

  • 如果需要監(jiān)視屬性值變更。可以在PropertyMetadata中定義一個(gè)PropertyChangedCallback方法。因?yàn)檫@個(gè)方法是靜態(tài)的,可以再實(shí)現(xiàn)一個(gè)同名的實(shí)例方法(可以參考ContentControl的OnContentChanged方法)。

  • 5.2 代碼段

    注冊依賴屬性的語法比較難記,可以使用VisualStudio自帶的代碼段propdp(輸入propdp后按兩次tab)自動(dòng)生成,這個(gè)代碼段生成的代碼只有基本功能,如下所示:

    public int MyProperty {get { return (int)GetValue(MyPropertyProperty); }set { SetValue(MyPropertyProperty, value); } }// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc... public static readonly DependencyProperty MyPropertyProperty =DependencyProperty.Register("MyProperty", typeof(int), typeof(MyPage), new PropertyMetadata(0));

    要生成完整的依賴屬性代碼,可以使用自定義的代碼段,以下代碼段生成的就是完整的依賴屬性定義,快捷鍵是dp:

    <?xml version="1.0" encoding="utf-8"?> <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"><CodeSnippet Format="1.0.0"><Header><Keywords><Keyword>dp</Keyword> </Keywords><SnippetTypes><SnippetType>SurroundsWith</SnippetType> </SnippetTypes><Title>Dependency Property</Title> <Author>dino.c</Author><Description>For Dependency Property</Description> <HelpUrl> </HelpUrl><Shortcut>dp</Shortcut> </Header><Snippet><References><Reference><Assembly></Assembly> </Reference></References> <Declarations> <Literal Editable="true"> <ID>int</ID><ToolTip>int</ToolTip> <Default>int</Default><Function></Function> </Literal><Literal Editable="true"><ID>MyProperty</ID> <ToolTip>屬性名</ToolTip><Default>MyProperty</Default> <Function> </Function></Literal> <Literal> <ID>defaultvalue</ID><ToolTip>默認(rèn)值</ToolTip> <Default>0</Default></Literal> <Literal Editable="false"> <ID>classname</ID><ToolTip>類名</ToolTip> <Function>ClassName()</Function><Default>ClassNamePlaceholder</Default> </Literal></Declarations> <Code Language="csharp" Kind="method body"> <![CDATA[ /// <summary> /// 獲取或設(shè)置$MyProperty$的值 /// </summary> public $int$ $MyProperty$ { get { return ($int$)GetValue($MyProperty$Property); } set { SetValue($MyProperty$Property, value); } } /// <summary> /// 標(biāo)識 $MyProperty$ 依賴屬性。 /// </summary> public static readonly DependencyProperty $MyProperty$Property = DependencyProperty.Register("$MyProperty$", typeof($int$), typeof($classname$), new PropertyMetadata($defaultvalue$,On$MyProperty$Changed)); private static void On$MyProperty$Changed(DependencyObject obj,DependencyPropertyChangedEventArgs args) { $classname$ target= obj as $classname$; $int$ oldValue = ($int$)args.OldValue; $int$ newValue = ($int$)args.NewValue; if (oldValue != newValue) target.On$MyProperty$Changed(oldValue, newValue); } protected virtual void On$MyProperty$Changed($int$ oldValue,$int$ newValue) { }]]> </Code></Snippet> </CodeSnippet> </CodeSnippets>

    6. Slider與OneWayBinding的"Bug"

    UWP的依賴屬性比起WPF有了大幅簡化,需要學(xué)習(xí)的地方少了很多,但是功簡化了也不一定是一件好事。譬如下面這個(gè)代碼:

    <StackPanel><Slider x:Name="SliderSource"Maximum="200" /> <Slider x:Name="SliderTarget" Maximum="100" Value="{Binding ElementName=SliderSource,Path=Value,Mode=OneWay}" /> </StackPanel>

    理想的情況下,拖動(dòng)SliderSource到100以后,因?yàn)镾liderTarget的Value已經(jīng)超過Maximum設(shè)置的100,所以沒有反應(yīng);再次把SliderSource拖動(dòng)到100以下,SliderTarget才會(huì)重新跟隨SliderSource改變。但實(shí)際上,之后無論再怎么拖動(dòng)SliderSource,SliderTarget都不會(huì)有反應(yīng)。
    估計(jì)所有繼承自RangeBase的控件都會(huì)有這個(gè)BUG,如果要寫一個(gè)RangeBase控件(包含Value,Minimum,Maximum三個(gè)double值的控件,Value必須在后兩個(gè)值的范圍之間),這是個(gè)很讓人煩惱的問題。既然現(xiàn)在知道Value會(huì)被Maximum及Minimum約束,那么就可以猜想到問題出在ValueProperty的PropertyChangedCallback函數(shù)中。產(chǎn)生這個(gè)BUG的原因可以參考下面的代碼。

    private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {RangeBase range = d as RangeBase;double minimum = range.Minimum;double maximum = range.Maximum;double value = (double)e.NewValue;double initialVal = (double)e.OldValue;if (value < minimum){SetValue(ValueProperty, minimum);}if (value > maximum){SetValue(ValueProperty, maximum);}range.OnValueChanged(initialVal, value); }

    實(shí)際的代碼要復(fù)雜些,但基本的邏輯就是這樣。如果新的Value值超過了Maximum或Minimum,就將Value重新設(shè)置為Maximum或Minimum,保證Value不會(huì)超過設(shè)定的范圍。在這個(gè)例子里,如果在這個(gè)函數(shù)開頭的位置調(diào)用 range.ReadLocalValue(range.ValueProperty),返回的是一個(gè)Binding,在結(jié)尾的位置調(diào)用,返回的則是double類型的100,因?yàn)檫@段代碼將Value由OneWay Binding覆蓋為maximum的double值了。

    在WPF中,這個(gè)問題并不存在,因?yàn)閃PF的依賴屬性可以使用CoerceValueCallback約束屬性值,而UWP的依賴屬性被簡化了,缺少這個(gè)功能。可以在網(wǎng)上用“Silverlight CoerceValue Helper”或“Silverlight CoerceValue Utils”等關(guān)鍵字試試搜索一些解決方案。為什么使用Silverlight的關(guān)鍵字來搜索?因?yàn)镾ilverlight同樣存在這個(gè)問題。雖然網(wǎng)上能找到不少解決方案,但以我的經(jīng)驗(yàn)來說沒有方案能很好地解決這個(gè)問題。最后我的解決方案如下:

    /// <summary> /// 不要使用OneWayBinding,只能使用TwoWayBinding /// </summary> public object MyProperty {get { return (object)GetValue(MyPropertyProperty); }set { SetValue(MyPropertyProperty, value); } }

    反正不是寫控件庫給別人用,寫個(gè)注釋并且和同事打聲招呼就算了。

    有興趣的話可以參考Silverlight RangeBase的源代碼,由于Silverlight和UWP比較接近,參考Silverlight的源碼基本就可以理解RangeBase的實(shí)現(xiàn)細(xì)節(jié)。
    RangeBase.cs
    這個(gè)是Silverlight的開源實(shí)現(xiàn)Moonlight的源碼,Moonlight的源碼對理解UWP、Silverlight都很有參考價(jià)值。順便一提,Silverlight的依賴屬性參考文檔也比UWP的依賴屬性參考文檔好用一些。

    提示: 為什么使用TwoWay Binding可以解決這個(gè)問題?OneWay Binding和TwoWay Binding的內(nèi)部行為不同。使用OneWay Binding的情況下,給SliderTarget.Value設(shè)置一個(gè)值,意思就只是SliderTarget的Value需要設(shè)置成一個(gè)新的值,舍棄了之前的Binding。在TwoWay Binding的情況下,設(shè)置一個(gè)值的意思不止是Value會(huì)成為那個(gè)新的值,同時(shí)綁定的對象也會(huì)更新成這個(gè)值,TwoWay Binding 理所當(dāng)然地不能被舍棄。

    7.參考

    依賴屬性概述
    自定義依賴屬性
    Silverlight 依賴項(xiàng)屬性概述

    總結(jié)

    以上是生活随笔為你收集整理的[UWP]依赖属性2:使用依赖属性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。