Разработка
31
Окт
2

Отображение в лукапе основного атрибута в зависимости от языка

В MS CRM лукап всегда отображает основное атрибут объекта, к которому он относится. Но если у Вас мульти язычная система, а в лукапе отображается справочник, то было бы логично отображать в лукапе значение на том языке, который выбран в настройках текущего пользователя.

Предположим, что Организация имеет лукап на справочник Городов. Каждый город имеет два обязательных поля: русской название и английское название. Теперь посмотрим, как с помощью плагина заставить отображаться соответствующее поле в зависимости от предпочитаемого языка пользователя.

В целом нам нужно обработать два события: открытие карточки и изменение в поле лукапа. С открытием карточки все понятно – это Retrieve нужного объекта. А вот с изменение лукапа интереснее. При открытии диалога выбора записи для лукапа происходит RetrieveMultiple и на этом все. Далее отрабатывают только скрипты. Если Вы заметили, то первая колонка в представлении лукапа – это всегда основной атрибут объекта. И его нельзя ни передвинуть (с первого места), ни заменить. Это потому что код на форме берет текстовое значение из первой колонки и использует его для отображения в лукапе. Соответственно, чтобы использовать в данном случаи плагин, нам нужно заменить значения в первом столбце на аналогичные значения другого языка (в данном примере английского).

Для этого эксперимента нам понадобится:

  • Объект Город (new_city) с двумя обязательными полями:
    • Название (RU) (new_name_ru) – основной атрибут;
    • Название (EN) (new_name_en).

    Оба этих поля вынесите во все Представление объекта Город (поскольку RetrieveMultiple срабатывает на все представления);

  • Лукап на объект Город на форме Организации.

Создайте плагин с таким кодом:

using System;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Crm.Sdk.Messages;

namespace mainAttribute
{
    public class AccRetrieve : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            try
            {
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

                // Поулчаем ссылку на нужный лукап
                Entity target = (Entity)context.OutputParameters["BusinessEntity"];
                EntityReference city = (EntityReference)target.Attributes["new_city"];

                // Если лукпап не заполнен - прекращаем выполнение
                if (city == null) return;

                // Если язык русский - прекращаем выполнение
                if (mainAttribute.LanguageRetriever.RetrieveLanguageForUser(service, context.UserId) == 1049) return;

                // Запрашиваем значение поля на английском языке
                Entity resultEntity = service.Retrieve(city.LogicalName, city.Id, new ColumnSet("new_name_en"));

                // Обновляем значение в лукапе
                city.Name = (string)resultEntity.Attributes["new_name_en"];
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Ошибка: ", ex);
            }
        }
    }

    public class CityRetrieveMultiple : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            try
            {
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
                // Если язык базовый – прекращаем выполнение
                if (mainAttribute.LanguageRetriever.RetrieveLanguageForUser(service, context.UserId) == 1049) return;

                // Получаем коллекцию объектов, предназначенную для вывода
                EntityCollection targetCollection = (EntityCollection)context.OutputParameters["BusinessEntityCollection"];

                // Просматриваем всю коллекцию
                foreach (Entity target in targetCollection.Entities)
                {
                    // Если нет одного из полей то прекращаем выполнением
                    if (!target.Attributes.Contains("new_name_ru") || !target.Attributes.Contains("new_name_en")) return;

                    // И меняем столбцы местами
                    string temp = target.Attributes["new_name_ru"] as string;
                    target.Attributes["new_name_ru"] = target.Attributes["new_name_en"];
                    target.Attributes["new_name_en"] = temp;
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("Ошибка: ", ex);
            }
        }
    }

    static class LanguageRetriever
    {
        public static Int32 RetrieveLanguageForUser(this IOrganizationService service, Guid userId)
        {
            // Возвращаем личные настройки текущего пользователя
            RetrieveUserSettingsSystemUserRequest request = new RetrieveUserSettingsSystemUserRequest();
            request.EntityId = userId;
            request.ColumnSet = new ColumnSet("uilanguageid");
            RetrieveUserSettingsSystemUserResponse UserSettingsResponse = (RetrieveUserSettingsSystemUserResponse)service.Execute(request);
            Entity objUserSettings = (Entity)UserSettingsResponse.Entity;

            // Возвращаем код предпочитаемого пользователем языка
            return (Int32)objUserSettings.Attributes["uilanguageid"];
        }
    }
}

Тут у нас два плагина и один вспомогательный класс:

  • AccRetrieve – заменяет отображаемое в лукапе значение на аналогичное, соответствующее языку текущего пользователя;
  • CityRetrieveMultiple – плагин меняет местами значения двух столбцов Представления. В данном случае это столбцы с названиями городов на русском и английском;
  • LanguageRetriever – данный класс с одним методом предназначен для возвращения кода предпочитаемого текущим пользователем языка.

Зарегистрируйте сборку в CRM и добавьте два шага:

  • AccRetrieve – пост Retrieve для объекта Организация;
  • CityRetrieveMultiple – пост RetrieveMultiple для объекта город.

Готово. Теперь языки корректно взаимозаменяются для нашего лукапа (а также во всех представлениях где вынесены оба поля).

Трюк

Если у Вас корректно переведены метки трансляций, то Вы обнаружите маленькую неприятность. При переключении на английской язык столбцы в диалоге лукапа будут отображаться корректно, но данных в них будут из другого языка. Чтобы «исправить» это переведите метки трансляции наоборот. Т.е., для данного примера – для поля «Название (EN)» задайте метку «Name (RU)», а для «Название (RU)» метку «Name (EN)».





Комментарии (2)
  • Антон 31.10.2012

    Спасибо за инфу!
    А можно ли просто изменять отображение основного атрибута по умолчанию? Ну например нужно мне выводить в лукап не new_name (основной для сущности), а new_custom.

  • slivka_83 31.10.2012

    не,т по умолчанию такого не сделать.

*

code