С выходом .Net 3.0 у нас появилась возможность дополнять базовые классы без их переопределения собственными методами. Данная технология получила название Code Extensions Methods
Но как оказалось, что таким же простым и очень гибким методом можно расширить возможности и XAML разметки окон и компонентов.
Простым примером использования extension можно привести всем хорошо знакомую конструкцию
Где Binding и есть ни что иное как расширения языка.
А теперь конкретный пример, исправляющий недостаток вышеупомянутой конструкции, когда сделать привязку к самому себе можно только через длинную строчку кода
Создадим собственное расширение SelfBinding:
1. Добавим в проект класс и обзовем его SelfBinding
2. Унаследуем данный класс от MarkupExtension
3. Добавим свойство Path типа string
4. Создадим пустой конструктор
5. Создадим конструктор с одним параметром string Path
6. Переопределим его метод ProvideValue
Теперь можно и проверить
Все получилось, теперь следует добавить возможность использовать конвертеры, как это сделано в стандартном Binding.
7. Добавим проперти Converter типа IValueConverter и проверим его при возращении результата
Все!
Ну и на закуску: Импортируем в стандартное пространство имен наш Namespase чтобы каждый раз нам не приходилось писать префикс перед каждым расширением. Добавьте в файл Assembly.cs следующую строчку и отбилдите проект
TODO:
1. Добавить триггер на изменение свойства, чтобы была живая привязка
2. Возможно реализовать задание пути в следующем виде: Path=Foreground.Name
Таким сбособом можно решить некоторые проблемы, например мы так соорудили поддержку мультиязычности, а также менеджера, который следил за отоброжением элементов на форме, в зависимости от прав пользователя.
Искодный код
Почитать по теме: Markup Extensions and XAML
WPF Multilanguage Markup Extension
Но как оказалось, что таким же простым и очень гибким методом можно расширить возможности и XAML разметки окон и компонентов.
Простым примером использования extension можно привести всем хорошо знакомую конструкцию
<Button Content="{Binding Path=Title}"/>
* This source code was highlighted with Source Code Highlighter.
Где Binding и есть ни что иное как расширения языка.
А теперь конкретный пример, исправляющий недостаток вышеупомянутой конструкции, когда сделать привязку к самому себе можно только через длинную строчку кода
<Button Content="{Binding Path=Height,
RelativeSource={RelativeSource Self}}"/>
* This source code was highlighted with Source Code Highlighter.
Создадим собственное расширение SelfBinding:
1. Добавим в проект класс и обзовем его SelfBinding
2. Унаследуем данный класс от MarkupExtension
3. Добавим свойство Path типа string
4. Создадим пустой конструктор
5. Создадим конструктор с одним параметром string Path
public SelfBinding(string Path)
{
this.Path = Path
}
* This source code was highlighted with Source Code Highlighter.
6. Переопределим его метод ProvideValue
public override object ProvideValue(IServiceProvider serviceProvider)
{
try
{
if (string.IsNullOrEmpty(Path))
throw new ArgumentNullException("Path", "The Path can not be null");
//Получим провайдер, с информацией об объектре и првязках
var providerValuetarget = (IProvideValueTarget)serviceProvider
.GetService(typeof(IProvideValueTarget));
//Получим объект, вызвавший привязку
DependencyObject _targetObject = (DependencyObject)providerValuetarget.TargetObject;
//Получим свойство для возвращения значения привязки
PropertyInfo _sourceProperty = _targetObject.GetType().GetProperty(Path);
//Вернем значение свойства
return _sourceProperty.GetValue(_targetObject,null);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return null;
}
}
* This source code was highlighted with Source Code Highlighter.
Теперь можно и проверить
<Window x:Class="for7raid.wpfExtension.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:for7raid.wpfExtension"
Title="Window1" Height="300" Width="300">
<Grid>
<Button Content="{local:SelfBinding Foreground}" />
</Grid>
</Window>
* This source code was highlighted with Source Code Highlighter.
Все получилось, теперь следует добавить возможность использовать конвертеры, как это сделано в стандартном Binding.
7. Добавим проперти Converter типа IValueConverter и проверим его при возращении результата
//Если у нас задан конвертер, прогоним значение через него
if (Converter != null)
return Converter.Convert(value, _targetProperty.PropertyType, null,
Thread.CurrentThread.CurrentCulture);
else
return value;
* This source code was highlighted with Source Code Highlighter.
Все!
Ну и на закуску: Импортируем в стандартное пространство имен наш Namespase чтобы каждый раз нам не приходилось писать префикс перед каждым расширением. Добавьте в файл Assembly.cs следующую строчку и отбилдите проект
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "for7raid.wpfExtension")]
* This source code was highlighted with Source Code Highlighter.
TODO:
1. Добавить триггер на изменение свойства, чтобы была живая привязка
2. Возможно реализовать задание пути в следующем виде: Path=Foreground.Name
Таким сбособом можно решить некоторые проблемы, например мы так соорудили поддержку мультиязычности, а также менеджера, который следил за отоброжением элементов на форме, в зависимости от прав пользователя.
<Button Content="{Title btnKey, Default=Hello button}",
Visability="{AllowedBy All sp1 sp2 sp3}"/>
* This source code was highlighted with Source Code Highlighter.
Искодный код
Почитать по теме: Markup Extensions and XAML
WPF Multilanguage Markup Extension