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 это делает то же самое. Надеюсь это поможет

Другие вопросы по тегам