title: How to find PropertyInfo about a DependencyProperty (on a DependencyObject) in WinUI 3
body: <p>Sometimes it's useful to have more information about a <code>DependencyProperty</code> than metadata supplies. For example, in generalized tracing methods and event handlers, it's helpful to be able to find the name (and other characteristics) of a <code>DependencyProperty</code> on a <code>DependencyObject</code>.</p>
  <p>In WinUI 3, <code>System.Reflection</code> reports <code>DependencyProperties</code> as <code>MemberType=Properties</code> so we use <code>GetProperties()</code> to get a <code>PropertyInfo[]</code> containing information on all properties on an object or type (WPF reports <code>DependencyProperties</code> as <code>MemberType=Fields</code> so we'd use <code>GetFields()</code> instead).</p>
  <p><code>DependencyProperties</code> are actually declared as <code>static</code> fields and the <code>Get...</code> methods in <code>Reflection</code> typically default to not listing static members. When calling <code>GetProperties</code>, be sure to include the <code>BindingFlags.Static</code> flag, as well as <code>BindingFlags.Public</code> to include public <code>DependencyProperties</code> in your list.</p>
  <p>Next, we check each of the returned <code>PropertyInfo[]</code> items to see if they are actually about the <code>DependencyProperty</code> identifier of interest. If <code>dp</code> holds the identifier of your <code>DependencyProperty</code> of interest and <code>pi</code> is the <code>PropertyInfo</code> item you're checking, use the <code>object.ReferenceEquals(pi.GetValue(sender), dp)</code> method to see if they both refer to the same identifier (Note: this will be false if <code>pi</code> and <code>dp</code> are on different objects or identify different properties). There should be one, and only one, match in the returned array.</p>
  <p>Here is the beginning of a <code>PropertyChanged</code> handler that demonstrates:</p>
  <pre><code>    private static void BoundPropertyChanged(DependencyObject sender, DependencyProperty dp)
      {
          // sender is DependencyObject upon which the dp changed
  
          PropertyInfo dpInfo = sender.GetType().GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
              .Where(pi =&gt; pi.PropertyType == typeof(DependencyProperty) &amp;&amp; object.ReferenceEquals(pi.GetValue(sender), dp)).Single();
  
          // Trace logic, etc.
      }
  </code></pre>
  <p>The first statement has four parts:</p>
  <ol>
  <li><code>sender.GetType().GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)</code> fetches information on all properties on sender's type. The <code>BindingFlags.FlattenHierarchy</code> flag means, essentially, include inherited properties, too.</li>
  <li><code>.Where(pi =&gt; pi.PropertyType == typeof(DependencyProperty)</code> selects only members that have a <code>PropertyType</code> of <code>DependencyProperty</code> (routed events might be in the list from 1), too).</li>
  <li><code>&amp;&amp; object.ReferenceEquals(pi.GetValue(sender), dp))</code> further limits the selected items to those that refer to the same identifiers.</li>
  <li>the <code>.Single();</code> clause selects the sole member of the resulting list and throws an error if there is more (or less) than one.</li>
  </ol>
  <p>One caveat is that this approach relies heavily on reflection, which is relatively slow.</p>
  <p>I don't know of a better way to do this, but I'd welcome suggestions and improvements!</p>