Width of string to the right of a point, in a bi-directional text

限于喜欢 提交于 2020-01-30 06:23:05

问题


*Sorry if the title is not great. I am not sure how to summarize this question into a few words.


I have a DataGridView and a search box. When the user types a query, any matching result in the DataGridView cells, is highlighted. To achieve this I use the CellPainting event of DataGridView and draw a rectangle behind the results.

Some of the cells are oriented Right-To-Left:

And some are oriented Left-To-Right:

When the orientation is RTL, I use the following formula to calculate the highlight rectangle X-coordinate:

e.CellBounds.Right - queryWidth - stringBeforeQueryWidth;

and stringBeforeQueryWidth refers to this:

When the orientation is LTR, I use the following formula:

e.CellBounds.Left + stringBeforeQueryWidth;

and stringBeforeQueryWidth refers to this:

The way I calculate stringBeforeQueryWidth is as follows:

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

So when the orientation is RTL, I use the fact that all the characters that come before the query itself will be drawn to the right of it, and when the orientation is LTR, I use the fact that all the characters that come before the query itself will be drawn to the left of it.

The problem starts when the cell contains a string that combines LTR and RTL texts. For example:

Let's say the query is 13. To calculate stringBeforeQueryWidth I need the width of רחוב ישראל ישראלי and the width of /5. I cannot use cellValue.Substring(0, cellValue.IndexOf(query)) to retrieve them, like I did when there was only one orientation, because רחוב ישראל ישראלי comes before the query, and /5 comes after the query.

So how can I get the width of the part of the string that is located to the right of the query?


回答1:


Note: This is not a direct answer to the question. It's an alternative.

As an option, you can show the search result in a HTML table and display it in WebBrowser control and highlight the search text using javascript.

To show search result as HTML, I'll use use T4 Run-time Text Templates. This way I can pass data to the html template and render the report easily by assigning output string of the template to a DocumentText property of the WebBrowser control. I've used this idea for creating simple and fast print document, for example take a look at this post.

TO highlight the text, you can use some javascript code or plugins. For example you can take a look at this post.

Here is result of the example which I will share in this post:

Example

  1. Create a Form and drop a WebBrowser control and a ToolStrip control on it, like what you see in above image.

  2. Add the following .cs file to the project and paste the following code in the file:

    namespace Sample
    {
        public class ReportModel
        {
            public string RTL { get; set; }
            public string LTR { get; set; }
        }
    }
    
  3. Add a new RunTime Text Template item to the project and name it ReportTemplate.tt. Open the file and paste the following content. Here I've used this plugin to highlight the text. And passed a model to the t4 template to easily generate 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. Handle Load event of the form and turn off script errors and initialize sample data:

    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. Handle Click event of the search button and seach, and pass the search result to template and run the template and show the result in WebBrowser control:

    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. Handle DocumentCompleted event of the WebBrowser and call InvokeScript method of Document object and call highlight javascript function which we have already created in the 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. Run the application and type 123 in the text box and press search button to see the result.



来源:https://stackoverflow.com/questions/54574412/width-of-string-to-the-right-of-a-point-in-a-bi-directional-text

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!