Система анимации WPF имеет возможность устанавливать под-свойства объектов, а синтаксический анализатор XAML - нет.
Два обходных пути:
- В установщике свойств InternalControl возьмите переданное значение и выполните итерацию по его свойствам DependencyProperties, копируя их в ваш фактический InternalControl.
- Использование события сборки для программного создания вложенных свойств для всех свойств внутреннего контроля.
Я объясню каждый из них по очереди.
Установка свойств с помощью установщика свойств
Это решение не приведет к упрощенному синтаксису, который вы желаете, но оно простое в реализации и, вероятно, решит основную проблему, состоящую в том, как объединить значения, установленные в вашем контроле контейнера, со значениями, установленными во внутреннем контроле.
Для этого решения вы продолжаете использовать XAML, который вам не понравился:
<my:CustomButton Something="Abc">
<my:CustomButton.InternalControl>
<thirdparty:MyThirdPartyButton Content="ClickMe" />
</my:CustomButton.InternalControl>
но на самом деле вы не заменяете свой InternalControl.
Для этого установщик вашего InternalControl будет:
public InternalControl InternalControl
{
get { return _internalControl; }
set
{
var enumerator = value.GetLocalValueEnumerator();
while(enumerator.MoveNext())
{
var entry = enumerator.Current as LocalValueEntry;
_internalControl.SetValue(entry.Property, entry.Value);
}
}
}
Вам может потребоваться дополнительная логика для исключения DP, которые не видны публично или которые установлены по умолчанию. На самом деле это легко сделать, создав фиктивный объект в статическом конструкторе и составив список DP, которые по умолчанию имеют локальные значения.
Использование события сборки для создания вложенных свойств
Это решение позволяет писать очень симпатичный XAML:
<my:CustomButton Something="Abc"
my:ThirdPartyButtonProperty.Content="ClickMe" />
Реализация заключается в автоматическом создании класса ThirdPartyButtonProperty в событии сборки. Событие сборки будет использовать CodeDOM для создания вложенных свойств для каждого свойства, объявленного в ThirdPartyButton, которое еще не отражено в CustomButton. В каждом случае PropertyChangedCallback для присоединенного свойства будет копировать значение в соответствующее свойство InternalControl:
public class ThirdPartyButtonProperty
{
public static object GetContent(...
public static void SetContent(...
public static readonly DependencyProperty ContentProperty = DependencyProperty.RegisterAttached("Content", typeof(object), typeof(ThirdPartyButtonProperty), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
((CustomButton)obj).InternalControl.Content = (object)e.NewValue;
}
});
}
Эта часть реализации проста: сложная часть создает задачу MSBuild, ссылается на нее из вашего .csproj и упорядочивает ее так, чтобы она выполнялась после прекомпиляции my: CustomButton, чтобы она могла видеть, какие дополнительные свойства необходимы добавить.