#wpf #data-binding #datatemplate
#wpf #привязка к данным #datatemplate
Вопрос:
Используя WPF, я хочу привязать заголовок GroupBox к имени типа полиморфного класса. Итак, если у меня есть класс с именем Element и два класса, производных от Element, такие как BasicElement и AdvancedElement, я хочу, чтобы в заголовке GroupBox было написано «BasicElement» или «AdvancedElement». Вот xaml, который я использую для GroupBox. Это часть DataTemplate, используемой ItemsControl. Я надеюсь на что-то вместо Path=DerivedTypeNameOf(group) в XAML, где group — это каждая группа в массиве groups.
Обратите внимание, что ObjectInstance для данных устанавливается в допустимый экземпляр GroupSet, который содержит массив некоторых базовых групп и расширенных групп.
Вот соответствующие классы, лежащие в основе кода:
public class Group
{
public string groupName;
public string df_groupName
{
get { return this.groupName; }
set { this.groupName = value; }
}
}
public class BasicGroup : Group
{
}
public class AdvancedGroup : Group
{
}
public class GroupSet
{
public Group [] groups;
public Group [] df_groups
{
get { return this.groups; }
set { this.groups = value; }
}
};
Вот XAML:
<UserControl.Resources>
<ResourceDictionary>
<ObjectDataProvider x:Key="TheData" />
<DataTemplate x:Key="GroupTemplate">
<GroupBox Header="{Binding Path=DerivedTypeNameOf(group)}">
<TextBox Text="This is some text"/>
</GroupBox>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
<ItemsControl ItemsSource="{Binding Source={StaticResource TheData}, Path=groups}" ItemTemplate="{StaticResource GroupTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Ответ №1:
Вы всегда можете использовать ValueConverter для получения типа:
public class TypeNameConverter : IValueConverter {
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture) {
return value.GetType().Name;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture) {
throw NotImplementedException();
}
}
Это позволило бы вам иметь любой тип в вашей коллекции без какой-либо необходимости в реализации свойства для получения значения. В противном случае просто сделайте, как говорит Дэвид, и реализуйте свойство для получения результата. Вам даже не нужно было бы реализовывать это в каждом классе, если существует общее наследование от базового класса. Просто реализуйте это в базе с помощью GetType().Name, и вы всегда получите правильное значение.
Ответ №2:
Почему бы просто не добавить
public abstract string DerivedTypeName { get; set; }
к вашему базовому классу и переопределяет его для каждого производного типа, тогда вы просто привязываетесь к строке.