Check what field was clicked in MS Word - c#

I need to add a command to right click menu in Word shown after clicking field.
That wasn't a problem:
var ContextMenu = this.Application.CommandBars["Fields"];
button = (Office.CommandBarButton)ContextMenu.Controls.Add(1);
button.Click += new Office._CommandBarButtonEvents_ClickEventHandler(button_Click);
Now I need to get the field user clicked. I tried this:
void button_Click(Office.CommandBarButton Ctrl, ref bool cancel)
{
var currentSelection = Globals.ThisAddIn.Application.ActiveWindow.Selection;
if (currentSelection.Fields.Count > 0)
var field = currentSelection.Fields[1]
//Do some stuff with the field
}
But it will only work if the field is selected, it won't work for example when user just right clicked it without selecting anything or selected only part of fields displayed text.

You can significantly reduce the number of fields you iterate by checking currentSelection.Range.Paragrahs[1].Fields.

I came up with this solution but still looking for something that won't have to iterate throught all fields in document:
public static IEnumerable<Field> GetAllFieldsInSelection(this Selection selection)
{
foreach (Field f in selection.Document.Fields)
{
int fieldStart = f.Code.FormattedText.Start;
int fieldEnd = f.Code.FormattedText.End + f.Result.Text.Count();//field code + displayed text lenght
if (!((fieldStart < selection.Start) & (fieldEnd < selection.Start) |
(fieldStart > selection.End) & (fieldEnd > selection.End)))
{
yield return f;
}
}
}

Related

How to provide the index of the clicked button which is created dynamically by instance?

I am trying to pass the index of the clicked button in Repeat(int value) and wrote this -
gp.GetComponentInChildren ().onClick.AddListener(() =>
Repeat(rep));
But when I click any button I got the last index of the button for all.
I want to know is there any way, I can pass the index of that button which i clicked in Repeat()?
void chatDialogs() {
foreach (Transform child in this.transform) {
GameObject.Destroy (child.gameObject);
}
for (int i = 5; i > 0 ; i--) {
int currentStep = Laststep - i;
if (currentStep >= 0) {
gp = (GameObject)Instantiate (playerPreFab);
gp.transform.SetParent (this.transform);
}
gp.GetComponentInChildren<Button> ().onClick.AddListener(() =>
Repeat(**transform.GetSiblingIndex()**));
}
public void Repeat(int speakstep) {
Application.ExternalCall("textspeak", speakstep);
}
in speakstep object of Repeat() the clicked button index should be passed, but its getting the last index in every button I click.
I think you can do something like this:
AddButtonListener(gp.GetComponentInChildren<Button> (), i);
inside your for loop,
when AddButtonListener is defined as:
void AddButtonListener(Button b, int index)
{
b.onClick.AddListener(()=>{Repeat(index)});
}
This way you capture the button index in the listener function (but I'm not sure what the correct name of this pattern is), and I wrote this without actually running it. Hope you have enough info now to get it working.

How to assign values for check boxes for a formula calculation which includes a text box in the formula

I am a new programmer learning to code in C# and I have an C# assignment to be finished and for that I need to make some formulas to calculate rent for tours and for that I decided to use text boxes and check boxes in C# but I cant figure out how to make a formula with the combination of check boxes and a text box.
private void button1_Click_1(object sender, EventArgs e)
{
checkBox1.Text = "50000";
checkBox2.Text = "250000";
checkBox3.Text = "2500";
checkBox4.Text = "10000";
checkBox5.Text = "1500";
if (checkBox1.CheckState == CheckState.Checked &&
checkBox2.CheckState == CheckState.Checked)
{
}
}
The type of control has little to do with creating a formula. To create the formula, you need to know all it's possible inputs and how they should be combined to produce the output. This could be done in a method, for example:
private int GetTotalValue(int vehiclePrice, int driverPrice, int rentDuration)
{
// This is where your formula would go
return (vehiclePrice + driverPrice) * rentDuration;
}
The trick then, is to convert the state of the form controls into values that you can plug into the method. One way to do this (not necessarily the best way, but probably easiest to understand when you're starting) is to check the value of each control and set the appropriate value in the Click event for your Submit button.
For the rent duration, we can use the int.TryParse method, which takes in a string and an "out" int parameter, and returns true if the string is a valid integer, or false if it's not. When it exits, if the conversion was successful, the out parameter will contain the int value.
For the other controls, we could use simple if / else if statements to determine which control was checked, and then set our value accordingly. In this example, we're using temporary variables inside the click event to store the value for each parameter to the method. If none of the required controls are checked, we can show a message to the user and wait for them to finish filling out the form.
In this example I used radio buttons (and used the opt prefix, which is a naming convention from a long time ago that I'm not sure still exists - they used to be called option buttons):
private void btnSubmit_Click(object sender, EventArgs e)
{
// Validate that rent textbox contains a number
int rentDuration;
if (!int.TryParse(txtRentDuration.Text, out rentDuration))
{
MessageBox.Show("Please enter a valid number for rent duration");
return;
}
// Determine vehicle price based on which option was selected
int vehiclePrice;
if (optToyotaPrado.Checked) vehiclePrice = 50000;
else if (optRollsRoyce.Checked) vehiclePrice = 250000;
else if (optSuzikiWagonR.Checked) vehiclePrice = 2500;
else if (optToyotaCorolla.Checked) vehiclePrice = 10000;
else
{
MessageBox.Show("Please select a vehicle");
return;
}
// Determine driver price
int driverPrice;
if (optWithDriver.Checked) driverPrice = 1500;
else if (optWithoutDriver.Checked) driverPrice = 0;
else
{
MessageBox.Show("Please select a driver option");
return;
}
// Finally set the text to the return value of our original method,
// passing in the appropriate values based on the user's selections
txtTotalValue.Text = GetTotalValue(vehiclePrice, driverPrice, rentDuration).ToString();
}
As Rufus said, I'd go with RadioButtons, instead of CheckBoxes. Set the Tag property of the RadioButtons to the vaule you want associated with them and then use a function like this to get the value of the checked item. Just pass in the GroupBox to the function and get back the value of the checked RadioButton.
private int GetGroupBoxValue(GroupBox gb)
{
int nReturn = 0;
foreach (Control ctl in gb.Controls)
{
if (ctl.GetType() == typeof(RadioButton))
{
if (((RadioButton)ctl).Checked)
{
nReturn = Convert.ToInt32(ctl.Tag);
break;
}
}
}
return nReturn;
}
Now all you have to do is use the excellent code Rufus provided for checking for an integer in the rentDuration TextBox and you're golden.

How to invoke element in a WebBrowser by the class name(s)?

I'm trying to make a simple Facebook client. One of the features should allow the user to post content on the homepage/his profile.
It logs the user in (works fine, all of the elements have got ids on Facebook) and then inserts the data in the corresponding field (works fine as well), but then it needs to click the "Post" button. However, this button doesn't have any id. It only has got a class.
<li><button value="1" class="_42ft _4jy0 _11b _4jy3 _4jy1 selected _51sy" data-ft="{"tn":"+{"}" type="submit">Posten</button></li>
('Posten' is 'Post' on German.)
I've been looking around the internet for a few hours now and tried different solutions. My most current solution is to search the item by it's inner content ("Posten") and then invoke it. Doesn't work. It inserts the text but doesn't invoke the button. Here's the code:
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (postHomepage)
{
webBrowser1.Document.GetElementById("u_0_z").SetAttribute("value", metroTextBox1.Text);
GetButtonByInnerText("Posten").InvokeMember("click");
postHomepage = false;
}
}
HtmlElement GetButtonByInnerText(string SearchString)
{
String data = webBrowser1.DocumentText;
//Is the string contained in the website
int indexOfText = data.IndexOf(SearchString);
if (indexOfText < 0)
{
return null;
}
data = data.Remove(indexOfText); //Remove all text after the found text
//These strings are a list of website elements
//NOTE: These need to be updated with ALL elements from list such as:
// http://www.w3.org/TR/REC-html40/index/elements.html
string[] strings = { "<button" };
//Split the string with these elements.
//subtract 2 because -1 for index -1 for elements being 1 bigger than wanted
int index = (data.Split(strings, StringSplitOptions.None).Length - 2);
HtmlElement item = webBrowser1.Document.All[index];
//If the element is a div (which contains the search string
//we actually need the next item.
if (item.OuterHtml.Trim().ToLower().StartsWith("<li"))
item = webBrowser1.Document.All[index + 1];
//txtDebug.Text = index.ToString();
return item;
}
(This is a quick solution which I edited for my use, not very clean).
What's wrong here?
It does not look like your GetButtonByInnerText() method is searching for the button element correctly.
Here is simple replacement for you to try:
HtmlElement GetButtonByInnerText(string SearchString)
{
foreach (HtmlElement el in webBrowser1.Document.All)
if (el.InnerText==SearchString)
return el;
}

Wpf Richtextbox selection starting column and row number returns different values

I am initializing my Richtextbox,
void InitRTBFlowDocument()
{
Style noSpaceStyle = new Style(typeof(Paragraph));
noSpaceStyle.Setters.Add(new Setter(Paragraph.MarginProperty, new Thickness(0)));
rtbTextEditor.Resources.Add(typeof(Paragraph), noSpaceStyle);
}
I want to get Richtext box selection words row and column numbers. I wrote the code as follows, First time it is returning correctly.
void rtbTextEditor_SelectionChanged(object sender, RoutedEventArgs e)
{
//Get the richtext box selected text
Init.RTBSelectionText = rtbTextEditor.Selection.Text.Trim();
Init.SelectionText = rtbTextEditor.Selection.Text.Trim();
Init.isSelect = true;
if (Init.RTBSelectionText != string.Empty)
{
TextPointer tp = rtbTextEditor.Selection.Start.GetPositionAtOffset(-2, LogicalDirection.Forward);
if (tp != null)
GetStartingIndex();
}
Init.RTBContent = new TextRange(rtbTextEditor.Document.ContentStart, rtbTextEditor.Document.ContentEnd).Text;
}
void GetStartingIndex()
{
TextPointer tp1 = rtbTextEditor.Selection.Start.GetLineStartPosition(0);
TextPointer tp2 = rtbTextEditor.Selection.Start;
int SelectionColumnIndex = tp1.GetOffsetToPosition(tp2)-1;//column number
int someBigNumber = int.MaxValue;
int lineMoved;
rtbTextEditor.Selection.Start.GetLineStartPosition(-someBigNumber, out lineMoved); //Line number
int SelectionRowIndex = -lineMoved;
Init.RTBTextPoint = new RTBTextPointer();
Init.RTBTextPoint.Row = SelectionRowIndex;
Init.RTBTextPoint.Column = SelectionColumnIndex;
}
After clearing and added new content, The position returns wrong number,
public void DisplayContent(string content)
{
//Clear the rich text box
rtbTextEditor.Document.Blocks.Clear();
rtbTextEditor.Document.Blocks.Add(new Paragraph(new Run(content)));
}
Is anything rong in the above code.
Please help me
Thanks in advance!
This is because the contents in the RTB does not only contain text, it contains these things called TextPointerContext's. TextPointer's take this into account. You can check what the TextPointer is adjacent to by using:
TextPointer.GetPointerContext(LogicalDirection);
To get the next TextPointer:
TextPointer.GetNextContextPosition(LogicalDirection);
Some sample code I used in a recent project, this makes sure that the pointer context is of type Text:
while (start.GetPointerContext(LogicalDirection.Forward)
!= TextPointerContext.Text)
{
start = start.GetNextContextPosition(LogicalDirection.Forward);
if (start == null) return;
}
When you clear your RTB, you're probably removing some of these pointer contexts. So be careful when using GetPositionAtOffset(). This should give you a "pointer" in the right direction. If you need any more help me know.
Good hunting!

How can I right-align accelerator text in a Windows.Controls.ContextMenu menuitem?

In the Win32 API, the tab character (\t) is used to display right-aligned text (like for accelerators / shortcuts) in a menu item ("Open\tCtrl+O"). In a C# app, I have a class derived from System.Windows.Controls.ContextMenu and it appears that using the tab character in a similar manner does not achieve the same result; it actually inserts a tab, so the shortcut looks more center-aligned than right-aligned.
I know that in .net _ is used in place of the Win32 & for mnemonic underlines. Is there a similar substitute for \t?
Edit: code for context (without the ICommand implementation)
internal class MyContextMenu : ContextMenu, ICommand
{
private readonly string[] wordList;
public MyContextMenu(string aWord)
{
var itemStyle = (Style) TryFindResource("EditorContextMenuItem");
wordList = GetMyWordList(aWord);
if (wordList != null)
{
for (int i = 0; i < wordList.Length; ++i)
{
string word = wordList[i];
var item = new MenuItem
{
Style = itemStyle,
Header = BuildMenuText(i + 1, word),
Command = this,
CommandParameter = i
};
this.Items.Add(item);
}
}
}
static private string BuildMenuText(int index, string text)
{
string menuText;
if (index > 0 && index < 16)
menuText = text + "\t_" + index.ToString("x");
else
menuText = "_" + text;
return menuText;
}
}
Set your accelerator text to the MenuItem.InputGestureText property.
Also, note the remark in the documentation page: This property does not associate the input gesture with the menu item; it simply adds text to the menu item. The application must handle the user's input to carry out the action. For information on how to associate a command with a menu item, see Command.

Categories

Resources