WPF DataGrid: CellEditingTemplate ComboBox несколько данных для CellTemplate TextBox
Я гуглил вокруг, но с очень ограниченной удачей. У меня есть вопрос относительно редактируемой WPF DataGrid; в CellEditingTemplate показан ComboBox, но в CellTemplate показан TextBox с соответствующим значением ComboBox. Мой код выглядит примерно так:
<DataGridTemplateColumn Header="Unit">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="comboBoxUnit" ItemsSource="{Binding ...}" SelectedValue="{Binding UnitId, ValidatesOnDataErrors=True}" SelectedValuePath="Id">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="<would like to have selected Unit's Id and Name here>" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Как мне этого добиться? Отдельное свойство в классе (чтобы иметь свойства UnitId и UnitName) не проблема, я могу добавить его, но как тогда связать оба с ComboBox? Могу ли я получить доступ к CellEditingTemplate ComboBox в CellTemplate? Кажется, что они находятся в "разных пространствах имен", так как я могу именовать элементы управления в обоих именах...
Есть идеи, указатели? Заранее спасибо, БД
1 ответ
Самый простой способ добиться того же - использовать DataGridComboBoxColumn
,
Тем не менее, в моем текущем проекте у нас было так много проблем с DataGridComboBoxColumn
что мы его больше не используем. Вместо этого мы используем DataGridTemplateColumn
с ComboBox
в CellEditingTemplate
и TextBlock
в CellTemplate
(так же, как вы делаете).
Чтобы иметь возможность отображать данные на основе идентификатора (чтобы получить те же функции в TextBlock
как в ComboBox
) мы используем конвертер под названием CodeToDescriptionConverter
, Это можно использовать как это
<TextBlock>
<TextBlock.Text>
<MultiBinding>
<MultiBinding.Converter>
<con:CodeToDescriptionConverter CodeAttribute="Id"
StringFormat="{}{0} - {1}">
<con:CodeToDescriptionConverter.DescriptionAttributes>
<sys:String>Id</sys:String>
<sys:String>Name</sys:String>
</con:CodeToDescriptionConverter.DescriptionAttributes>
</con:CodeToDescriptionConverter>
</MultiBinding.Converter>
<Binding Path="UnitId"/>
<Binding Path="Units"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
- Первый
Binding
это значение, которое мы ищем (Id) - Второй
Binding
этоIList
мы смотрим в CodeAttribute
имя свойства, которое мы хотим сравнить с идентификатором (сначалаBinding
)DescriptionAttributes
свойства, которые мы хотим вернуть, отформатированы какStringFormat
И в вашем случае: найти экземпляр в Units
где собственность Id
имеет то же значение, что и UnitId
и для этого экземпляра вернуть значения Id
а также Name
отформатированный как {0} - {1}
CodeToDescriptionConverter
использует отражение, чтобы достичь этого
public class CodeToDescriptionConverter : IMultiValueConverter
{
public string CodeAttribute { get; set; }
public string StringFormat { get; set; }
public List<string> DescriptionAttributes { get; set; }
public CodeToDescriptionConverter()
{
StringFormat = "{0}";
DescriptionAttributes = new List<string>();
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length != 2 ||
values[0] == DependencyProperty.UnsetValue ||
values[1] == DependencyProperty.UnsetValue ||
values[0] == null ||
values[1] == null)
{
return null;
}
string code = values[0].ToString();
IList sourceCollection = values[values.Length - 1] as IList;
object[] returnDescriptions = new object[DescriptionAttributes.Count];
foreach (object obj in sourceCollection)
{
PropertyInfo codePropertyInfo = obj.GetType().GetProperty(CodeAttribute);
if (codePropertyInfo == null)
{
throw new ArgumentException("Code Property " + CodeAttribute + " not found");
}
string codeValue = codePropertyInfo.GetValue(obj, null).ToString();
if (code == codeValue)
{
for (int i = 0; i < DescriptionAttributes.Count; i++)
{
string descriptionAttribute = DescriptionAttributes[i];
PropertyInfo descriptionPropertyInfo = obj.GetType().GetProperty(descriptionAttribute);
if (descriptionPropertyInfo == null)
{
throw new ArgumentException("Description Property " + descriptionAttribute + " not found");
}
object descriptionObject = descriptionPropertyInfo.GetValue(obj, null);
string description = "";
if (descriptionObject != null)
{
description = descriptionPropertyInfo.GetValue(obj, null).ToString();
}
returnDescriptions[i] = description;
}
break;
}
}
// Ex. string.Format("{0} - {1} - {2}", arg1, arg2, arg3);
return string.Format(StringFormat, returnDescriptions);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Я загрузил пример приложения здесь: https://dl.dropbox.com/u/39657172/CodeToDescriptionSample.zip.
Включает в себя DataGridTemplateColumn
с CodeToDescriptionConverter
и DataGridComboBoxColumn
это делает то же самое. Надеюсь это поможет