WPF DependencyProperty
2008-08-04 20:39
363 查看
oSection1:Briefintroduction
1.CLRpropertiesarereallyjustsafewrappersaroundaPrivatemembervariable:
privateintx;
publicintX
{
get{returnx;}
set{x=value;}
}
DependencyProperty(DP)ismorethanjustsimpleCLRproperties,ThefollowingtableillustratessomeofthethingsthatcanbeacheivedbytheuseofDPs:
AchievableitemsthankstoDPs |
ChangeNotification |
Callbacks |
Propertyvaluevalidation |
Propertyvalueinheritence* |
Participationinanimations* |
ParticipationinStyles* |
ParticipationinTemplates* |
Databinding |
Layoutchanges* |
Overridingdefaultdatavalues* |
DeclareadependencyProperty(Alwayspublicstaticreadonly)
InitialisethedependencyProperty,eitherusingDependencyProperty.RegisterAttached/DependencyProperty.Register/DependencyProperty.RegisterReadOnly/DependencyPropertyRegisterAttachedReadOnly
Declareget/setpropertywrapper(seecodebelow)
publicclassMyStackPanel:StackPanel
{
publicstaticreadonlyDependencyPropertyMinDateProperty;
staticMyStackPanel()
{
MinDateProperty=DependencyProperty.Register("MinDate",
typeof(DateTime),
typeof(MyStackPanel),
newFrameworkPropertyMetadata(DateTime.MinValue,
FrameworkPropertyMetadataOptions.Inherits));
}
publicDateTimeMinDate
{
get{return(DateTime)GetValue(MinDateProperty);}
set{SetValue(MinDateProperty,value);}
}
}
Belowistheregistermethod:
publicstaticDependencyPropertyRegister(stringname,TypepropertyType,TypeownerType,PropertyMetadatatypeMetadata,System.Windows.ValidateValueCallbackvalidateValueCallback)
ThelastparameteristhedelegateofValidateValuemethod.ForPropertyMetadataparameter,weuseFrameWorkPropertyMetadata,isthetypeusedfordependencypropertymetadata,ratherthanthebase
metadatatypesPropertyMetadataor
UIPropertyMetadata.Thisistruebothforexistingdependencypropertiesandformostcustomdependencypropertyscenarios.
publicFrameworkPropertyMetadata(objectdefaultValue,FrameworkPropertyMetadataOptionsflags,PropertyChangedCallbackpropertyChangedCallback,CoerceValueCallbackcoerceValueCallback):base(defaultValue,propertyChangedCallback,coerceValueCallback,boolisAnimationProhibited,UpdateSourceTriggerdefaultUpdateSourceTrigger)
Defaultvalues
Provideoneofthe
FrameworkPropertyMetadataOptionsvalues,suchasAffectsMeasure/AffectsArrange/AffectsRender/Inheritsetc
Propertychangedcallbackdelegates
Coersionvaluescallbackdelegates,canoperatevalue
Makeapropertyun-animatable
Provideoneofthe
UpdateSourceTrigger,suchasPropertyChanged/LostFocus/Explicitetc
oSection2:HowtheDependencyPropertyregisteredanduse
DependencyPropertyClasshasastatichashtableandlisttostoretheregistereddependencyProperty,ClassDependencyProperty
{………………
privatestaticHashtablePropertyFromName=newHashtable();
internalstaticItemStructList<DependencyProperty>RegisteredPropertyList=newItemStructList<DependencyProperty>(0x300);
…………………..}
MethodRegister
{………
DependencyPropertydp=newDependencyProperty(name,propertyType,ownerType,defaultMetadata,validateValueCallback);
………………..
PropertyFromName[key]=dp;
RegisteredPropertyList.Add(dp);
…………
if(typeMetadata!=null)
{
this.OverrideMetadata(ownerType,typeMetadata);
}
……….}
ThekeyinPropertyFromNameis“name.HashCode^ownerType.HashCode”.
TheValueofthisdictionaryistheinstanceofDependencyPropery.
ThenifclienthavenewFrameWorkMetaData,registrationwilladdthemetadataintoainstancemap,whichwillbeexplainedspecificallybelowinAddOwnermethod.
TakenoticethatthePropertyFromNamehashtableandRegisteredPropertyListarestatic,soallDPscanaccesstheseglobalhashtableandlist,andlet'sseewhatmembersareinstancemembersinDependencyPropertyclass:
ClassDependencyProperty
{
privatePropertyMetadata_defaultMetadata;
internalInsertionSortMap_metadataMap;
privatestring_name;
privateType_ownerType;
privateFlags_packedData;
privateType_propertyType;
privateDependencyPropertyKey_readOnlyKey;
privateSystem.Windows.ValidateValueCallback_validateValueCallback;
…………………
privateDependencyProperty(stringname,TypepropertyType,TypeownerType,PropertyMetadatadefaultMetadata,System.Windows.ValidateValueCallbackvalidateValueCallback)
{
FlagsuniqueGlobalIndex;
this._metadataMap=newInsertionSortMap();
this._name=name;
this._propertyType=propertyType;
this._ownerType=ownerType;
this._defaultMetadata=defaultMetadata;
this._validateValueCallback=validateValueCallback;}
…………………….
}
MostoftheinstancemembersareinitiatedinDP’sprivateconstructor.Whenregister,thefiled“_defaultMetadata”usedtostoreFrameWorkMetaData,thenwhat“_metadataMap”usedfor?Itusedtostoreothercontrols’metaData.
Now,wehaveregisteredMinDateProperty,thenifothercontrolneedtousethisproperty,itwilluseAddOwnermethodlikebelow:
publicDependencyPropertyAddOwner(TypeownerType,PropertyMetadatatypeMetadata)
{
if(typeMetadata!=null)
{
this.OverrideMetadata(ownerType,typeMetadata);
}
lock(Synchronized)
{
PropertyFromName[key]=this;
}
}
Ifregisteranewsamenameproperty,itwillhavenothingtodowithMyStackPanel.MinDatePropertyevenifuseinheritedflagandischildrenofMyStackPanel
publicpartialclassUserControlLabel:Label
{
publicstaticreadonlyDependencyPropertyMinDateProperty=MyStackPanel.MinDateProperty.AddOwner(typeof(UserControlLabel),
newFrameworkPropertyMetadata(DateTime.MinValue,FrameworkPropertyMetadataOptions.Inherits));
}
AddOwnermethodwillcallOverrideMetadatamethodtoSuppliesalternatemetadataforthisdependencypropertywhenitispresentoninstancesofaspecifiedtype,overridingthemetadatathatwasprovidedintheinitialpropertyregistration(whenregisteration,ifmetadataisnotnull,alsowillcallthismethodtoputmetadatainmap):
this._metadataMap[dType.Id]=typeMetadata;
Wecanseethismap,itskeyiscurrentDependencyObjecttype’sId,andvalueismetadata.Takeourprogramasexample:
Instancemember:_metadataMapinMyStackPanel.MindateProperty:
UserControlLabel.typeId | UserControlLabel‘sMinDateProperty.metaData |
MyStackPanel.typeId | MyStackPannel’sMinDatePropertymetaData |
InMinDateProperty.GetMetaData()method,itfirstfindmetadatathroughUserControlLabel’stypeId,ifcan’tfind,tryUserControlLabel’sbasetype,ifcan’teither,returntheMinDateProperty’sdefaultpropertymetaData.)所以在写onPropertyChanged方法时候,要判断sourceasStackPanel!=null,因为一个metadata可能被其他source用到,这时候source就不是stackPanel了。
thenadd<propertyname^ownerType,propertyinstance>toHashtablePropertyFromName,nowthehashtablecontainstwoelments,keyisdifferent,butvalueissame:
Staticmember:PropertyFromNamehashtableinMinDateProperty:
MinDate^StackPanel | StackPanel’sMinDatePropertyinstancemember |
MinDate^UserControl | StackPanel’sMinDatePropertyinstancemember |
namespaceSystem.Windows.Markup
internalclassBamlMapTable
{
internalDependencyPropertyGetDependencyProperty(BamlAttributeInfoRecordbamlAttributeInfoRecord)
{
if((bamlAttributeInfoRecord.DP==null)&&(bamlAttributeInfoRecord.PropInfo==null))
{
this.GetAttributeOwnerType(bamlAttributeInfoRecord);
if(bamlAttributeInfoRecord.OwnerType!=null)
{
bamlAttributeInfoRecord.DP=DependencyProperty.FromName(bamlAttributeInfoRecord.Name,bamlAttributeInfoRecord.OwnerType);}}returnbamlAttributeInfoRecord.DP;}}SomeTimesifweaddotherclass’sDPasamemberinmyclass,wecandirectlyuseoverrideMetadatamethodtooverridemetadata:
publicvoidOverrideMetadata(TypeforType,PropertyMetadatatypeMetadata)
ClassPage:Control
StaticPage
{
UIElement.FocusableProperty.OverrideMetadata(typeof(Page),newFrameworkPropertyMetadata(BooleanBoxes.FalseBox));
}
}
ThedifferencebetweenuseAddOwnermethodandoverrideMetadatamethodisthelastonedon’tneedtoadd<propertyname^ownerType,propertyinstance>toHashtablePropertyFromName.
UseOverrideMetaDatamethod意味着这个control并不想把这个Property作为自己的property,在xaml里可以直接设置了,也就是不必写.netproperty的包装,因为这个根本不是它的属性,一般用于attachedproperty或者基类的property来overridemetadata.
InDependencyPropertyClass,alsohavemethod:
publicstaticDependencyPropertyKeyRegisterReadOnly(stringname,TypepropertyType,TypeownerType,PropertyMetadatatypeMetadata,System.Windows.ValidateValueCallbackvalidateValueCallback)
Thismethodisusedtoregisteraread-onlydependencyproperty,italsowillnewaDPinstance,fillhashtableandmetamap,atlastreturnDependencyPropertyKeyclass:
publicsealedclassDependencyPropertyKey
{
//Fields
privateDependencyProperty_dp;
//Methods
internalDependencyPropertyKey(DependencyPropertydp);
publicvoidOverrideMetadata(TypeforType,PropertyMetatypeMetadata);
internalvoidSetDependencyProperty(DependencyPropertydp);
//Properties
publicDependencyPropertyDependencyProperty{get;}}
oSection3:HowtogetandSetPropertyValue
AllWPFclasswhichusedependencypropertyshouldinheritedDependencyObjectClass,inDependencyObject,ithasmethodsSetValue(DependencyPropertydp,boolvalue)tosetValueforonedependencyPropertyandpublicobjectGetValue(DependencyPropertydp)togetValueforonedependencyProperty.(Inprogram,codewillusepropertywrappertosetandgetvalue,butinxaml,willdirectlyuseSetValue()andGetValue()method).InDependencyObjectClass,itusesarray
privateEffectiveValueEntry[]_effectiveValues
tostorethedependencyProperty’svalue.TheEffectiveValueEntryisnotasimplevaluestructure,itincludesmuchinformationaboutthepipelinetogetvalue,youcanseeappendixpicturespecifically.
InSetValue(DependencyPropertydp,boolvalue),itfirstlygetpropertymetadataforthiscontrolfrom_metadataMapwhichIhavesaidinfrontsection.Howtogetit?Haven’tyouseethemap?ThroughtheXXXClass.typeId(PropertyMetadatametadata=this.SetupPropertyChange(dp))
SomeTimes,wedon’tknowtheinstanceofDependencyproperty,wecanalsogetitfromPropertyFromNameHashtable,usemethodbelowwhichisinDependencyPropertyclass.
[FriendAccessAllowed]
internalstaticDependencyPropertyFromName(stringname,TypeownerType).
Now,Let’ssavethevalueinto_effectiveValuesarray.Butbeforeit,therearecomplicatedthingstodo,becauseWPFcontainsmanypowerfulmechanismsthatindependentlyattempttosetthevalueofdependencyproperties.Ofcourse,astheirnameindicates,dependencypropertiesweredesignedtodependontheseprovidersinaconsistentandorderlymanner.
Thepicturebelowillustratesthefive-stepprocess(wecallitpipeline)thatWPFrunseachdependencypropertythroughinordertocalculateitsfinalvalue.Thisprocesshappensautomaticallythankstothebuilt-inchangenotificationindependencyproperties.
InSetValuemethod,itfirstlywillgetcorrespondingdependencyPropertyEffectiveValueEntry(ifalreadyhave,getit,ifnotalreadyhave,newit)._effectiveValuesisanarray,howdoIknowwhichelementismywant?_effectiveValuesarrayuseDependencyProperty’shashcodeasindex,thishashcodeiscalledDependencyProperty.GlobalIndex,itisgeneratedindependecyProperty‘sconstructor:
lock(Synchronized)
{
uniqueGlobalIndex=(Flags)GetUniqueGlobalIndex(ownerType,name);
RegisteredPropertyList.Add(this);
}
if(propertyType.IsValueType)
{
uniqueGlobalIndex|=Flags.IsValueType;
}
if(propertyType==typeof(object))
{
uniqueGlobalIndex|=Flags.IsObjectType;
}
if(typeof(Freezable).IsAssignableFrom(propertyType))
{
uniqueGlobalIndex|=Flags.IsFreezableType;
}
if(propertyType==typeof(string))
{
uniqueGlobalIndex|=Flags.IsStringType;
}
this._packedData=uniqueGlobalIndex;
GlobalIndex=(int)this._packedData)&0xffff;
}
Nextgotothepipeline,
Step1:“determineBaseValue”:
Thefollowinglistrevealstheeightprovidersthatcansetthevalueofmostdependencyproperties,inorderfromhighesttolowestprecedence:
1.Localvalue
2.Styletriggers
3.Templatetriggers
4.Stylesetters
5.Themestyletriggers
6.Themestylesetters
7.Propertyvalueinheritance
8.Defaultvalue
HereItakeinheritanceforexample;youwillseehowtheinheritanceisimplemented.Thecodeis:
if(!flag4&&metadata.IsInherited)
{
DependencyObjectinheritanceParent=this.InheritanceParent;
if(inheritanceParent!=null)
{
EntryIndexentry=inheritanceParent.LookupEntry(dp.GlobalIndex);
if(entry.Found)
{
flag4=true;
newEntry=inheritanceParent._effectiveValues[entry.Index].GetFlattenedEntry(RequestFlags.FullyResolved);
newEntry.BaseValueSourceInternal=BaseValueSourceInternal.Inherited;
}
}
}
Step2:Expression:Ifthevaluefromsteponeisanexpression(anobjectderivingfromSystem.Windows.Expression),thenWPFperformsaspecialevaluationsteptoconverttheexpressionintoaconcreteresult.
Step3:Animation:Ifoneormoreanimationsarerunning,theyhavethepowertoalterthecurrentpropertyvalue(usingthevalueafterstep2asinput)orcompletelyreplaceit.
Step4:ifinmetadata,havesetcoerceValueCallbackdelegate,willcallthisdelegatetooperatetthevalue.Thecodelike:
if((metadata.CoerceValueCallback!=null)
{
objectobj6=metadata.CoerceValueCallback(this,coersionBaseValue);
}
Step5:Whenregisterproperty,wesetValidateValueCallbackdelegate,willcalldelegatetovalidatethispropertyvalue.
(Mostoftheabove5processisinmethodbelow,evencanseeitasaneventtriggermethod:
InternalUpdateResultUpdateEffectiveValue(EntryIndexentryIndex,DependencyPropertydp,PropertyMetadatametadata,EffectiveValueEntryoldEntry,refEffectiveValueEntrynewEntry,boolcoerceWithDeferredReference,OperationTypeoperationType))
)
Afterthefivesteps,savetheEffectiveValueEntrywhichhasthevalueto_effectiveValues[DependencyProperty.GlobalIndex].
Don’tforgetwecanaddpropertyChangedCallbackdelegatetometadatawhenregestertheDP,atlastinsetValue(),ifvaluechanged,itwillcallthisdelegate:
if((isAValueChange)
{
this.NotifyPropertyChange(newDependencyPropertyChangedEventArgs(dp,metadata,isAValueChange,oldEntry,newEntry,operationType));
}
internalvoidNotifyPropertyChange(DependencyPropertyChangedEventArgsargs)
{
this.OnPropertyChanged(args);
………………………
}
ProtectedvirtualvoidOnPropertyChanged(DependencyPropertyChangedEventArgse)
{
if((e.IsAValueChange||e.IsASubPropertyChange)||(e.OperationType==OperationType.ChangeMutableDefaultValue))
{
PropertyMetadatametadata=e.Metadata;
if((metadata!=null)&&(metadata.PropertyChangedCallback!=null))
{
metadata.PropertyChangedCallback(this,e);
}
}
}
UseGetValue()methodtogetDepencyPropertyvaluefrom_effectiveValuesarrayusingDependencyProperty.GlobalIndex,ifhavenovalue,GetValuemethodwilltrytogetvaluefromdefault,orifhavesetinheritedflaginmetaData,itwilltrytogetvaluefromparent.
InDependencyObject,thereisoneusefulmethodClearValue(DependencyProperty),itcanclearthelocalvalue(becauseithashighestprecedence),andcallUpdateEffectiveValuemethodtorunthepipelinetogetvalueagain,andthismethodcancallPropertyChangeddelegatetoo.
oSection4:AttachedDependencyProperty
AttachedpropertiesarejustanotherstrainofDPs.UsingAttachedPropertiesweareabletouseDPsfromclassesthatareoutsideofthecurrentclass.1.RegisterAttachedDP:useRegisterAttachedmethod
publicclassMyStackPanel:StackPanel
{
publicstaticreadonlyDependencyPropertyIntDataProperty=DependencyProperty.RegisterAttached("IntData",
typeof(int),
typeof(MyStackPanel),
newFrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.Inherits,onIntdataChange,onIntdataCoreceValue),onIntdataValidate);}TheownerTypecanbenotDependencyObject,soRegisterAttachedwillnotcalloverrideMetaData.Because_metadataMapuseDependencyObjectType.typeIdaskey.
2.ProvidestaticGetPropertyNameandSetPropertyNamemethodsasaccessorsfortheattachedproperty.
publicclassMyStackPanel:StackPanel
{
publicstaticvoidSetIntData(UIElementelement,intvalue)
{
//actuallyDependencyObject.SetValue()
element.SetValue(IntDataProperty,value);
}
publicstaticintGetIntData(UIElementelement)
{
//actuallyDependencyObject.GetValue()
return(int)element.GetValue(IntDataProperty);
}
}
3.Useattachedproperty.
<Labelx:Name="myLabel"FontWeight="Bold"FontSize="20"Foreground="White"Panel.ZIndex="5"ab:MyStackPanel.IntData="4">
Thecorrespondingcodingaboutattachedpropertyis:
MyStackPanel.SetIntData(myLabel,4);
4.Effect.IfinMyStackPanel,IhavesetonPropertyChangedelegate,inthemethod,Icanoperatethelabelcontrolwhichhavechangedtheproperty.Inthiscodebelow,themylabel‘sbackgroundwillbesettopink.
privatestaticvoidonIntdataChange(DependencyObjecto,DependencyPropertyChangedEventArgse)
{
if(oisControl)
{
ControlsourceControl=oasControl;
sourceControl.Background=Brushes.Pink;
}
}
AttachedProperty’sfunction:
1.Canaddfunctionsforotherclassandnotchangingtheircode.Liketheupperstep4
2.Savedatato_EffectiveValue[],getitwhenneedtouseit:
<ButtonCanvas.Left=”18”Canvas.Top=”18”Background=”Orange”>Left=18,
What’sthedifferencebetweenDependencyProperty.RegisterAttached()andDependencyProperty.Register()?Justatthemetadata,RegisterAttachedmethodwillnotcallOverrideMetadatamethod,thismethodwilldotwothingswhichhavestatedinsection2,oneiscombinethebasetype’smetadatawithnewmetadata,theotherisaddmetadatatoinstancemember_metadataMap.Whytheattachepropertydon’tdothesetwothings,Ihavenotunderstoodit.
Althoughit,RegisterAttachedmethodstillwill“new”aDependencyPropertyinstance,additintostaticmember:RegisteredPropertyListandPropertyFromNamehashtablelikeRegistermethoddo
.
Wemustknowthis“IntDate”Dependencypropertyanditsvaluearebelongto“MyLabel”instance,notbelongto“MyStackPanel”instanceanymore.ThenwegettoknowwhyweshouldaddstaticGetPropertyNameandSetPropertyNamemethods.Itneeduse“MyLabel”’sSetValue()methodtostorethe“IntDate”DPanditsvalueinto“MyLabel”’s_effectiveValuesarray.
Then“MyLabel”willgetmetadatafromIntDataProperty,andtriggerthePropertyChangeCallBackandcoerceValueCallback,becausepassthe“MyLabel”instancetothesecallback,socanoperate“MyLabel”instance.
MyLabel’s_effectiveValues[]
Index=IntDataProperty.GlobalIndex Value=4 |
Appendix1:
Appendix2:
Appendix2:
Appendix3:
InregisterandAddOwnermethod,theyallwillusetheOverrideMetadatamethod:publicstaticDependencyPropertyRegister(stringname,TypepropertyType,TypeownerType,PropertyMetadatatypeMetadata,System.Windows.ValidateValueCallbackvalidateValueCallback)
{
PropertyMetadatadefaultMetadata=null;
if((typeMetadata!=null)&&typeMetadata.DefaultValueWasSet())
{
defaultMetadata=newPropertyMetadata(typeMetadata.DefaultValue);
}
DependencyPropertyproperty=RegisterCommon(name,propertyType,ownerType,defaultMetadata,validateValueCallback);
if(typeMetadata!=null)
{
property.OverrideMetadata(ownerType,typeMetadata);
}
returnproperty;
}
OverrideMetaDatamethod:
publicvoidOverrideMetadata(TypeforType,PropertyMetadatatypeMetadata)
{
DependencyObjectTypetype;
PropertyMetadatametadata;
this.SetupOverrideMetadata(forType,typeMetadata,outtype,outmetadata);
this.ProcessOverrideMetadata(forType,typeMetadata,type,metadata);
}
Isaidinsection2,itsmainjobisaddingnewmetadatato_metadataMapstructure.ButalreadyhaveconfusingissuewhichIdon’tunderstand.
privatevoidSetupOverrideMetadata(TypeforType,PropertyMetadatatypeMetadata,outDependencyObjectTypedType,outPropertyMetadatabaseMetadata)
{
//getawrapperstructDependencyObjectTypewhichwrapetheownertype
dType=DependencyObjectType.FromSystemType(forType);
//getownertype’sdirectlybasetype’smetadata
baseMetadata=this.GetMetadata(dType.BaseType);
}
privatevoidProcessOverrideMetadata(TypeforType,PropertyMetadatatypeMetadata,DependencyObjectTypedType,PropertyMetadatabaseMetadata)
{
lock(Synchronized)
{
//setmapIhavesaidinsection2
this._metadataMap[dType.Id]=typeMetadata;
}
typeMetadata.InvokeMerge(baseMetadata,this);
typeMetadata.Seal(this,forType);
}
Theconfusingissueis“typeMetadata.InvokeMerge”method,itseemscombinethebasetype’smetadatawithcurrentmetadata:
protectedvirtualvoidMerge(PropertyMetadatabaseMetadata,DependencyPropertydp)
{
if(baseMetadata.PropertyChangedCallback!=null)
{
Delegate[]invocationList=baseMetadata.PropertyChangedCallback.GetInvocationList();
if(invocationList.Length>0)
{
System.Windows.PropertyChangedCallbacka=(System.Windows.PropertyChangedCallback)invocationList[0];
for(inti=1;i<invocationList.Length;i++)
{
a=(System.Windows.PropertyChangedCallback)Delegate.Combine(a,(System.Windows.PropertyChangedCallback)invocationList[i]);
}
a=(System.Windows.PropertyChangedCallback)Delegate.Combine(a,this._propertyChangedCallback);
this._propertyChangedCallback=a;
}
}
if(this._coerceValueCallback==null)
{
this._coerceValueCallback=baseMetadata.CoerceValueCallback;
}
}
Incode,itseemstocombinethisDP’spropertyChangeCallbackwithbaseMetaData’spropertyChangeCallback,andifthis._coerceValueCallback==null,usebaseMetadata.CoerceValueCallback.
ButIhavemadeanexperiment:
publicclassMyStackPanel:StackPanel
{
publicstaticreadonlyDependencyPropertyMinDateProperty;
staticMyStackPanel()
{
MinDateProperty=DependencyProperty.Register("MinDate",
typeof(DateTime),
typeof(MyStackPanel),
newFrameworkPropertyMetadata(DateTime.MinValue,FrameworkPropertyMetadataOptions.Inherits,onMindateChange,onMindateCoreceValue),onMindateValidate);}publicDateTimeMinDate
{
get{return(DateTime)GetValue(MinDateProperty);}set{SetValue(MinDateProperty,value);}}…………………}publicclassMyStackPanel2:MyStackPanel
{
publicstaticreadonlyDependencyPropertyMinDateProperty=DependencyProperty.Register("MinDate",
typeof(DateTime),
typeof(MyStackPanel2),newFrameworkPropertyMetadata(DateTime.MinValue,
FrameworkPropertyMetadataOptions.Inherits,onMindateChange2),onIntdataValidate);
publicnewDateTimeMinDate
{
get{return(DateTime)GetValue(MinDateProperty);}set{SetValue(MinDateProperty,value);}}privatestaticvoidonMindateChange2(DependencyObjecto,DependencyPropertyChangedEventArgse)
{}}It’sapity,whensetvalueforMyStackPanel2.Mindate,itwilltriggeronMindateChange2method,itsparentMyStackPanel.onMindateChangewillnotbetriggered,sodotheonMindateCoreceValue.
So,Idon’tknowthemergeinoverrideMetadataisusedforwhat?
相关文章推荐
- WPF里的DependencyProperty(5)
- WPF里的DependencyProperty(4)
- WPF里的DependencyProperty(4)
- WPF Background property does not point to a dependencyobject in path '(0).(1)'
- WPF中的依赖属性(Dependency Property)
- .NET: WPF DependencyProperty
- WPF里的DependencyProperty(5)
- WPF里的DependencyProperty(5)
- WPF学习笔记8: 依赖属性(Dependency Property)
- WPF里的DependencyProperty(5)
- WPF - WPF Fundamentals - Properties - Dependency Property Metadata
- WPF里的DependencyProperty(3)
- WPF 依赖属性,用户控件依赖属性(DependencyProperty 依赖属性、GetValue() SetValue() CLR属性包装器、SetBinding 数据绑定)
- 有点理解WPF中的DependencyProperty(关联属性)了~
- WPF里的DependencyProperty(5)
- WPF中的Dependency Property(1)
- WPF Unleashed Chapter 3:Important New Concepts in WPF ---Dependency Properties(Property Value Inheritance)
- WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性
- WPF 轻松监听属性值的改变 神奇类:DependencyPropertyDescriptor
- WPF的Dependency Property System——出自《IT168》