Прикачени свойства на WPF контроли

Все още работя върху автоматизирано тестване на WPF приложения. Трябва да осъществя достъп до свойства по име, за да постигна това.

В момента се чудя за прикачени свойства на WPF контроли. Опитах се да премина през всички свойства на обект Button, мислейки, че мога да намеря и прикачени свойства. Но не можах да ги намеря.

Така че проверих с помощта на Snoop и той изброява много свойства като „KeyboardNavigation.AcceptsReturn“ и „ToolTipManager.ToolTipKey“, които трябва да бъдат прикачени свойства AFAIK.

Използвах следния код, за да създам списък с имена на (прикачени) свойства на "обект" на бутона:

   Type^ type = object->GetType();
   while (type)
   {
      array<FieldInfo^>^ fi = type->GetFields(BindingFlags::DeclaredOnly | BindingFlags::Static | BindingFlags::Public);
      for (int i=0; i<fi->Length; i++)
      {
         DependencyProperty^ dp = dynamic_cast<DependencyProperty^>(fi[i]->GetValue(object));
         if (dp)
         {
            DependencyPropertyDescriptor^ dpd = DependencyPropertyDescriptor::FromProperty(dp, type);
            if (dpd->IsAttached)
            {
               propertyNames->Add(fi[i]->Name);
            }
         }
      }

      type = type->BaseType;
   }

IsAttached обаче винаги е невярно и полученият lsit е празен. Без проверката „IsAttached“ получавам хубав списък със свойства, но без нито едно от очакваните прикачени свойства.

Не отразява ли списъка с прикачените свойства по този начин?


Мисля, че вече разбирам по-добре използването на прикачените свойства. Въпреки това всъщност не можах да разреша проблема си. Споменатият локален изброител получава само свойствата, които са зададени на обекта локално, а не всички свойства, налични за обекта.

Моля, позволете ми да обясня какво възнамерявам: Започвам само с името на прикачен имот... Първо трябва да проверя дали този прикачен имот съществува (което вероятно означава, че е регистриран, нали? ). След това искам да извлека стойността на прикаченото свойство, която може да бъде локално зададената стойност за моя обект (ако е зададен такъв) или стойността по подразбиране в противен случай.

В момента не знам как да проверя дали съществува прикачено свойство. Може би има някаква функция, предоставяща списък на всички налични прикачени свойства? Мога да го използвам за валидиране на дадено име на свойство и за извличане на съответния обект на свойство.


person Silicomancer    schedule 15.04.2013    source източник


Отговори (2)


Съжалявам, работата ме занимаваше. Бихте могли да направите това:

Ако приемем xaml:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>

    <Button x:Name="btn" Grid.Column="1"/>

</Grid>

Следният код трябва да ви даде някои опции:

    //do this if you can:
    btn.GetValue(Grid.ColumnProperty);

    //Otherwise,
    //gets all the dependency properties in the app domain
    Type depType = typeof(DependencyProperty) ;
    FieldInfo info = depType.GetField("PropertyFromName", BindingFlags.NonPublic | BindingFlags.Static);
    Hashtable AllDependencyProperties = info.GetValue(null) as Hashtable;

    //Index the hashtable of all dependency properties using a FromNameKey type            
    Type FromNameKeyType = depType.Assembly.GetType("System.Windows.DependencyProperty+FromNameKey");            
    ConstructorInfo ctor = FromNameKeyType.GetConstructor(new Type[] { typeof(String), typeof(Type) });
    var NameKey = ctor.Invoke(new object[] { "Column", typeof(Grid) });

    //index the hashtable to get the Dependency property
    DependencyProperty dp = AllDependencyProperties[NameKey] as DependencyProperty;

    //use the dp to get the value
    btn.GetValue(dp);


    //Or, without indexing a list of all dependency properties
    //get a dependency property by name
    System.Reflection.MethodInfo FromNameMethod = depType.GetMethod("FromName",System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic );
    var ret = FromNameMethod.Invoke(null, new object[] { "Column", typeof(Grid) });

    //use it to get a value from an object
    btn.GetValue((ret as DependencyProperty));

Предупреждение: това използва частни членове и класове, които MS може да промени в някоя бъдеща версия.

person A Aiston    schedule 18.04.2013
comment
Много хубаво, благодаря! Този код прави това, което искам, имам нужда само от няколко модификации. Колко жалко, че се нуждае от детайли за вътрешна реализация и че няма официален API за това. - person Silicomancer; 21.04.2013
comment
Това, което все още ме кара да се чудя (но не ми пречи да използвам кода) е какво точно прави snoop... С вашия код получавам много по-голям списък от прикачени (и неприкачени) свойства на зависимости. По някакъв начин Snoop изглежда филтрира прикачените свойства по отношение на избрания обект. - person Silicomancer; 21.04.2013
comment
Първо си помислих, че само онези прикачени свойства на зависимост (ADP), където са изброени от Snoop, които имат локално зададени стойности в избрания обект. Но това не е фактът. Всъщност повечето от ADP, изброени от Snoop, нямат локална стойност за избрания обект. Така че трябва да има друго обяснение. Знаете ли дали има някакъв начин за проверка на ADP за някаква уместност по отношение на обект или неговия тип? - person Silicomancer; 21.04.2013

Прикачените свойства се различават от нормалните свойства на зависимост по няколко начина. Най-забележимото е, че те не са обвити в CLR свойства (т.е. стандартни .NET свойства).

Разгледайте http://joshsmithonwpf.wordpress.com/2007/06/22/overview-of-attached-properties-in-wpf/ за повече подробности.

Може да искате да опитате да използвате GetLocalValueEnumerator, за да итерирате вашите свойства http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.getlocalvalueenumerator.aspx

person A Aiston    schedule 15.04.2013