Ширина строки справа от точки в двунаправленном тексте

* Извините, если название не очень. Я не уверен, как обобщить этот вопрос в нескольких словах.


У меня есть DataGridView и окно поиска. Когда пользователь вводит запрос, подсвечивается любой соответствующий результат в DataGridView ячейках. Для этого я использую событие CellPainting для DataGridView и рисую прямоугольник позади результатов.

Некоторые ячейки ориентированы справа налево:

введите здесь описание изображения

А некоторые ориентированы слева направо:

введите здесь описание изображения

Когда ориентация RTL, я использую следующую формулу для вычисления координаты X прямоугольника выделения:

e.CellBounds.Right - queryWidth - stringBeforeQueryWidth;

и stringBeforeQueryWidth относится к этому:

введите здесь описание изображения

Когда ориентация LTR, я использую следующую формулу:

e.CellBounds.Left + stringBeforeQueryWidth;

и stringBeforeQueryWidth относится к этому:

введите здесь описание изображения

Я вычисляю stringBeforeQueryWidth следующим образом:

var stringBeforeQuery = cellValue.Substring(0, cellValue.IndexOf(query));
var stringBeforeQueryWidth =
    e.Graphics.MeasureString(stringBeforeQuery, font, e.CellBounds.Width, format).Width;

Итак, когда ориентация RTL, я использую тот факт, что все символы, стоящие перед самим запросом, будут отрисовываться справа от него, а когда ориентация LTR, я использую тот факт, что все символы, стоящие перед запросом сама будет нарисована слева от него.

Проблема начинается, когда ячейка содержит строку, которая объединяет тексты LTR и RTL. Например: введите здесь описание изображения

Допустим, запрос 13. Чтобы вычислить stringBeforeQueryWidth, мне нужна ширина רחוב ישראל ישראלי и ширина /5. Я не могу использовать cellValue.Substring(0, cellValue.IndexOf(query)) для их извлечения, как делал, когда была только одна ориентация, потому что רחוב ישראל ישראלי идет перед запросом, а /5 — после запроса.

введите здесь описание изображения

Итак, как я могу получить ширину части строки, расположенной справа от запроса?


person Sipo    schedule 07.02.2019    source источник
comment
@DanielReyhanian - Пожалуйста, пишите на английском языке для тех, кто не понимает иврит. В любом случае, какая часть смущает вас? Пожалуйста, скажите мне, чтобы я мог улучшить вопрос.   -  person Sipo    schedule 07.02.2019
comment
на что ссылается queryWidth?   -  person Daniel Reyhanian    schedule 07.02.2019
comment
И не могли бы вы объяснить, что вы имеете в виду под запросом?   -  person Daniel Reyhanian    schedule 07.02.2019
comment
Это похоже на математическую задачу. Я бы предложил разбить предложение на нужные части (RTL и LTR) и провести расчет по каждой из них, как вы это делали раньше. Затем объедините результаты.   -  person Daniel Reyhanian    schedule 07.02.2019
comment
@DanielReyhanian - запрос - это то, что искал пользователь (выделено желтым цветом). queryWidth — это предварительно рассчитанная ширина самого запроса с использованием e.Graphics.MeasureString().   -  person Sipo    schedule 07.02.2019
comment
@DanielReyhanian - я думал об этой идее. Проблема в том, что что-то LTR или RTL не предсказывает, будет ли оно отображаться справа или слева от запроса. Мне нужен способ определить, какой из символов нарисован на какой стороне запроса. Кроме того, пожалуйста, просмотрите мое редактирование для получения дополнительной информации.   -  person Sipo    schedule 07.02.2019
comment
проверьте этот. Может быть, попробовать установить текстовое поле таким образом, чтобы оно всегда было RTL или LTR? Попробуйте отформатировать его, как это сделал парень в вопросе (тоже на иврите :))   -  person Daniel Reyhanian    schedule 07.02.2019
comment
@DanielReyhanian Спасибо. Связанный вопрос не о С#... Кроме того, это не TextBox, а ячейка DataGridView. Если у вас есть решение для кода, поделитесь им в ответе. Спасибо за ваше время.   -  person Sipo    schedule 07.02.2019
comment
.MeasureCharacterRanges может помочь, если он поддерживает биди.   -  person Jeroen Mostert    schedule 07.02.2019
comment
@JeroenMostert - Не могли бы вы уточнить ответ?   -  person Sipo    schedule 07.02.2019
comment
Это потребовало бы, чтобы я фактически создал эту ситуацию, написал код и протестировал его, все, на что мне не хватает времени (в отличие от привода с помощью комментария, предупреждающего вас о существовании метода).   -  person Jeroen Mostert    schedule 07.02.2019
comment
@JeroenMostert - Хорошо, спасибо. Я не уверен, как это поможет мне. Я имею в виду, что MeasureString у меня не работает, просто я не могу понять, какую строку в нее передать... Как мне изолировать все символы, которые визуально находятся справа от запроса?   -  person Sipo    schedule 07.02.2019
comment
Я надеялся, что .MeasureCharacterRanges позволит вам просто захватить область, где находится текст для выделения (используя пользовательский CharacterRanges), поскольку именно здесь вы собираетесь рисовать прямоугольник. .MeasureString не может знать о происходящем смешивании биди, потому что остальная часть строки вырезана, но .MeasureCharacterRanges может (хотя, как я уже сказал, я не знаю, делает ли это на самом деле).   -  person Jeroen Mostert    schedule 07.02.2019
comment
Пробовал с MeasuerCharacterRanges. Та же проблема.   -  person Sipo    schedule 08.02.2019


Ответы (1)


Примечание. Это не прямой ответ на вопрос. Это альтернатива.

Как вариант, вы можете показать результат поиска в таблице HTML и отобразить его в элементе управления WebBrowser и выделить текст поиска с помощью javascript.

Чтобы отобразить результаты поиска в формате HTML, я буду использовать текстовые шаблоны времени выполнения T4. Таким образом, я могу передавать данные в шаблон html и легко отображать отчет, назначая выходную строку шаблона свойству DocumentText элемента управления WebBrowser. Я использовал эту идею для создания простого и быстрого документа для печати, например, взгляните на этот пост.

Чтобы выделить текст, вы можете использовать код JavaScript или плагины. Например, вы можете взглянуть на этот пост.

Вот результат примера, которым я поделюсь в этом посте:

введите здесь описание изображения

Пример

  1. Создайте элемент Form и поместите на него элемент управления WebBrowser и элемент управления ToolStrip, как показано на изображении выше.

  2. Добавьте в проект следующий файл .cs и вставьте в него следующий код:

    namespace Sample
    {
        public class ReportModel
        {
            public string RTL { get; set; }
            public string LTR { get; set; }
        }
    }
    
  3. Добавьте в проект новый элемент RunTime Text Template и назовите его ReportTemplate.tt. Откройте файл и вставьте следующее содержимое. Здесь я использовал этот плагин чтобы выделить текст. И передал модель в шаблон t4, чтобы легко генерировать HTML:

    <#@ template language="C#"#>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ parameter name="Model" type="System.Collections.Generic.List<Sample.ReportModel>"#>
    <!DOCTYPE html>
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=11" />
        <title></title>
        <style type="text/css">
            body { font-family: Calibri;}
            table { text-align:center; border-collapse: collapse;}
            table, th, td { border: 1px solid black; }
            th {background-color: #EEEEEE;}
            th , td {padding: 2px;}
            .container { width:100%; height:100%; }
            .highlight { background: yellow; }
            .rtl {direction: rtl; text-align: right;}
            .ltr {direction: ltr; text-align: left;}
        </style>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script src="https://johannburkard.de/resources/Johann/jquery.highlight-5.js"></script>
        <script>
        function highlight(text) {
            $('#container').highlight(text);
        }
        </script>
    </head>
    <body>
    <div id ="container" class="container">
    <table style="width:100%">
        <tr>
            <th style="width:50%">LTR</th>
            <th style="width:50%">RTL</th>
        </tr>
        <#
        foreach(var item in Model) 
        {
        #>
        <tr>
            <td class="ltr"><#=item.LTR#></td>
            <td class="rtl"><#=item.RTL#></td>
        </tr>
        <#
        }
        #>
    </table>
    <div>
    </body>
    </html>
    
  4. Обработайте событие Load формы и отключите ошибки скрипта и инициализируйте демонстрационные данные:

    List<ReportModel> list;
    private void Form1_Load(object sender, EventArgs e)
    {
        webBrowser1.ScriptErrorsSuppressed = true;
        list = new List<ReportModel>()
        {
            new ReportModel(){ LTR = "Text 123 text", RTL = "متن 123 متن" }  ,
            new ReportModel(){ LTR = "Text 123 text", RTL = "متن 123 متن" }  ,
            new ReportModel(){ LTR = "Text 456 text", RTL = "متن 456 متن" }  ,
            new ReportModel(){ LTR = "Text 456 text", RTL = "متن 456 متن" }  ,
            new ReportModel(){ LTR = "Text 456 text", RTL = "متن 456 متن" }  ,
            new ReportModel(){ LTR = "Text 456 text", RTL = "متن 456 متن" }  ,
        };
    }
    
  5. Обработайте событие Click кнопки поиска и поиска, передайте результат поиска в шаблон, запустите шаблон и отобразите результат в элементе управления WebBrowser:

    private void searchButton_Click(object sender, EventArgs e)
    {
        var txt = searchTextBox.Text;
        var rpt = new ReportTemplate();
        rpt.Session = new Dictionary<string, object>();
        rpt.Session["Model"] = list.Where(x => x.LTR.Contains(txt) ||
            x.RTL.Contains(txt)).ToList();
        rpt.Initialize();
        webBrowser1.DocumentText = rpt.TransformText();
    }
    
  6. Обработайте событие DocumentCompleted объекта WebBrowser и вызовите метод InvokeScript объекта Document и вызовите функцию highlight javascript, которую мы уже создали в html:

    private void webBrowser1_DocumentCompleted(object sender,
        WebBrowserDocumentCompletedEventArgs e)
    {
        var txt = searchTextBox.Text;
        if (!string.IsNullOrEmpty(txt))
            webBrowser1.Document.InvokeScript("highlight",
                new object[] { txt });
    }
    
  7. Запустите приложение, введите 123 в текстовое поле и нажмите кнопку поиска, чтобы увидеть результат.

person Reza Aghaei    schedule 13.02.2019