Remove Content Control when Text is edited programmatically - c#

As per MSDN (emphasis mine):
If the Temporary property is true, the ContentControl is automatically deleted when the user types in the control, or when the text in the control is changed programmatically. When the ContentControl is automatically deleted from the document, the text in the control remains in the document.
It's working for "when the user types in the control" using Word Editor, but not when I change Text in (C#) code. My code is as below.
Make a tag Temporary
static void MakeTagsTemporary(List<Tag> tagList)
{
tagList.ForEach(x => x.Parent.Append(new TemporarySdt() { Val = true }));
} mainPart.Document.Save();
I am saving specifically to accept changes of making the Content Control Temporary, but with no effect.
Edit the text
static void ApplyProductGrid(MainDocumentPart mainPart, Plan pl, List<Tag> tagList)
{
foreach (Tag tagitem in tagList)
{
string GridValue = pl.FormattedTags.Where(x => x.Key == tagitem.Val).Select(x => x.Value).FirstOrDefault();
tagitem.Parent.Parent.Descendants<Text>().FirstOrDefault().Text = GridValue;
}
}
The line tagitem.Parent.Parent.Descendants<Text>().FirstOrDefault().Text = GridValue; is doing its job, its updating the value but Content Control is not removed.
When I edit something from word, Content Control is getting deleted.

Related

Reset part of application settings

So, I have Form called Preferences with TabControl in it. This TabControl contains several TabPages(General, Advanced, Misc, ...) with few comboboxes, checkboxes and labels. Each of this control inside TabPage is assigned Application Settings Property Binding (aka they show saved user settings, user can change them etc...).
I know that there is a method to reset all settings (Properties.Settings.Default.Reset();), but is there a way how to reset only settings inside one TabPage?
My solution is to iterate thru controls in TabPage, check if it is combobox, label etc and then reset it´s value to default, but is there a "oneliner" solution to this ?
Use the following solution to get the original value of a single setting:
(The example assumes you want to get the ORIGINAL value of a setting named 'Username')
var defaultUsername = Properties.Settings.Default.GetType()
.GetProperty(nameof(Properties.Settings.Default.Username))
.GetCustomAttribute<System.Configuration.DefaultSettingValueAttribute>()
.Value;
Important - this solution will always return a string value. make sure to parse it properly, or use this extension method I wrote:
public static T GetDefaultValue<T>(this ApplicationSettingsBase settings, string settingKey)
{
return (T)Convert.ChangeType(settings.GetType()
.GetProperty(settingsKey)
.GetCustomAttribute<DefaultSettingValueAttribute>()
.Value, typeof(T));
}
Usage:
var defaultNumber = Properties.Settings.Default.GetDefaultValue<int>(nameof(Properties.Settings.Default.Number));
The ApplicationSettings doesn't have built-in support to reset just some properties. But to solve the problem, you can use either of these options:
Create a method which resets all bound controls of a TabPage
Using Multiple Settings Files with Designer Support
Option 1 - Create a method which resets all bound controls of a TabPage
You can create a method which look at controls of the tab page and check if it's bound to application settings, find the property in settings and reset its value to the default value. Then you can reset settings of a TebPage width one line of code: ResetSettings(tabPage1);.
Here is the method:
private void ResetSettings(TabPage tabPage)
{
foreach (Control c in tabPage.Controls)
{
foreach (Binding b in c.DataBindings)
{
if (b.DataSource is ApplicationSettingsBase)
{
var settings = (ApplicationSettingsBase)b.DataSource;
var key = b.BindingMemberInfo.BindingField;
var property = settings.Properties[key];
var defaultValue = property.DefaultValue;
var type = property.PropertyType;
var value = TypeDescriptor.GetConverter(type).ConvertFrom(defaultValue);
settings[key] = value;
//You can also save settings
settings.Save();
}
}
}
}
Option 2 - Using Multiple Settings Files with Designer Support
If the reason of using a single settings file is because of designer support, you should know you can have designer support also with multiple settings files. Then you can use different settings files and reset each settings group separately. You can simply encapsulate them in a single class using such code:
public static class MySettings
{
public static Sample.General General
{
get { return Sample.General.Default; }
}
public static Sample.Advanced Advanced
{
get { return Sample.Advanced.Default; }
}
public static void ResetAll()
{
General.Reset();
Advanced.Reset();
}
public static void SaveAll()
{
General.Save();
Advanced.Save();
}
}
To reset a setting group it's enough to call MySettings.General.Reset();
To reset all settings, you can call MySettings.ResetAll();
Note for design-time support
To have designer support for binding properties to settings, create multiple settings files in root of your project. Don't put settings files in folders. The setting picker, only shows Settings.settings file which is in Properties folder and those files which are in root of project. This way you can see different settings files and settings properties in a tree-view like this:
TabPage page = aTabControl.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
//do stuff
}
Try this:
private void button2_Click(object sender, EventArgs e)
{
TabPage page = tabControl1.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
if(control is TextBox)
{
//do stuff
}
if(control is ComboBox )
{
ComboBox comboBox = (ComboBox)control;
if (comboBox.Items.Count > 0)
comboBox.SelectedIndex = 0;
comboBox.Text = string.Empty;
}
}
}

Updating NodeView cells in GTK#

How to make a NodeView cell retain the entered value after text's been entered through keyboard and the Edited event fired?
Whenever I enter some text into the cell and try to confirm that change, the old value that was there before my editing comes back.
The property of the subclass that should hold the value of a node never gets updated with the new value.
How do I get the text entered into a NodeView cell in the first place?
The trick is to use the Path property of the Gtk.EditedArgs argument passed to your event handler to get the correct node from the store and modify (you're responsible to propagate the change from the UI to your model). A small, complete example follows.
Given the following Gtk.TreeNode implementation:
[Gtk.TreeNode]
public class MyTreeNode : Gtk.TreeNode
{
public MyTreeNode(string text)
{
Text = text;
}
[Gtk.TreeNodeValue(Column=0)]
public string Text;
}
it is easy to change the Text property as follows:
Gtk.NodeStore store = new Gtk.NodeStore(typeof(MyTreeNode));
store.AddNode(new MyTreeNode("The Beatles"));
store.AddNode(new MyTreeNode("Peter Gabriel"));
store.AddNode(new MyTreeNode("U2"));
Gtk.CellRendererText editableCell = new Gtk.CellRendererText();
Gtk.NodeView view = new Gtk.NodeView(store);
view.AppendColumn ("Artist", editableCell, "text", 0);
view.ShowAll();
editableCell.Editable = true;
editableCell.Edited += (object o, Gtk.EditedArgs args) => {
var node = store.GetNode(new Gtk.TreePath(args.Path)) as MyTreeNode;
node.Text = args.NewText;
};
Note:
the use of args.Path to get the correct MyTreeNode from the store; and
the cast of the result to MyTreeNode to be able to access the Text property.

VSTO Word Add-In : Content Control Nesting

I'm building an MS-Word Add-In for the company where I'm doing my internship.
I already created a new ribbon with lots of SplitButtons and Buttons.
Now what i want to do is when you click one of the buttons a content control will ba added to the word doc.
This works fine for Plain Content Controls. These content controls have tags like "sport/basketball/player/name" which is binded to an element in an XML file.
private void addSimpleContentControl(String tag, String placeholder)
{
try
{
contentControlPlain = Globals.ThisAddIn.Application.ActiveDocument.ContentControls.Add(Microsoft.Office.Interop.Word.WdContentControlType.wdContentControlText);
contentControlPlain.Tag = tag;
contentControlPlain.SetPlaceholderText(null, null, placeholder);
}
catch (COMException) { }
}
Now let's talk about my problem.
Some of my elements could be present for more then one time. So what i want to create is a Rich Content control which holds more than one Plain content control.
So i have a SplitButton "player" with buttons like "name","jersey number","position",.....
When one of the underlying buttons is clicked i first check if a rich text control with a specific name already exist.
If not than i make one and add one single Plain content control to it.
Rich content control-> plain text control -> end of Rich content control
So far so good, this all goes fine but from the moment i want to add another plain content control to the rich content control this pops up :
"Plain text controls cannot be inserted around other controls or XML elements"
here is my code to add a plain content control to a rich content control.
private void addContentControlToRich(String tag, String placeholder,String title)
{
Microsoft.Office.Interop.Word.Document doc = Globals.ThisAddIn.Application.ActiveDocument;
foreach (Microsoft.Office.Interop.Word.ContentControl cc in doc.ContentControls)
{
if (cc.Title == title && cc.Type == Microsoft.Office.Interop.Word.WdContentControlType.wdContentControlRichText)
{
try
{
Microsoft.Office.Interop.Word.Range rng = cc.Range;
object oRng = rng;
contentControlPlain = doc.ContentControls.Add(Microsoft.Office.Interop.Word.WdContentControlType.wdContentControlText, ref oRng);
contentControlPlain.Tag = tag;
contentControlPlain.SetPlaceholderText(null, null, placeholder);
contentControlPlain.LockContentControl = true;
break;
}
catch (COMException) { }
}
}
}
instead of
contentControlPlain = doc.ContentControls.Add(Microsoft.Office.Interop.Word.WdContentControlType.wdContentControlText, ref oRng);
use
contentControlPlain = richTextControl.Range.ContentControls.Add(Microsoft.Office.Interop.Word.WdContentControlType.wdContentControlText, ref oRng);
before using above code use code below
Application.Selection.Start = lastControlinRichTextControl.Range.End+1;
and set `oRng = Application.Selection.Range
As per the message, your code is trying to wrap a plain text control around everything in the rich text control (ie an existing plain text control). Fix your range object so that it doesn't do that eg collapse it to just a point inside the rich text control.

Saving and loading TextBox or other control values with a text file

I know that this is possible to be done with application settings, but I want to do it this way:
I have some textboxes and other controls that have Text property. I am doing a loop and save the Name and Text property of them in a text file. The saving statement is like:
if (ctrl != null) sb.AppendLine(ctrl.Name.ToString() + ":" + ctrl.Text);
When I want to load them back I want to do it this way, but since I can not point to the Name of the controls, I am stuck! (I beleive it was possible in PHP to point to a variable using other variables!)
using (StreamReader file = new StreamReader(ofile.FileName))
{
while((line = file.ReadLine()) != null)
{
if (line.StartsWith("#")) continue; //Line is a commment so skip
else
{
data = line.Split(':');
//How to set back the text property to the variable?
}
}
}
What I have in mind now, is to save Tag property of controls instead of theire Name property. But the problem is my controls are all scaterred in side nested panels and stuff like that so I have to do a lot of LOOPING! to compare theire tags with tags avilable in my saved file (note that I am not going to save all controls in the text file, just some of em!)
What to do ?
You can find control by it's name if you have access to form's Controls property
var textBox = yourForm.Controls.Find("name", true) as TextBox;
if(textBox != null)
textBox.Text = "text";
Store all your controls in a key value pair container where key is the name of the control and value is a reference to the control it self. You can use a Dictionary to store them. When loading back from the text file, use the key to find the appropriate control and set the text.
your question is unclear .what i understand is you want to write text property to a text file and later restore via txt file if so then its a straighforward solution [in Winform]
to save use the format control-name:text
later on load
use
this.Controls[<controlname>].Text=Text
i.e. in your context
while((line = file.ReadLine()) != null)
{
if (line.StartsWith("#")) continue; //Line is a commment so skip
else
{
string[] data = line.Split(':');
if(data.Length>0)
{
if(this.Controls.ContainsKey(data[0]))
{
if(this.Controls[data[0]] is TextBox)
{
//generic
// this.Controls[data[0]].Text=data[1];
//or use
((TextBox) this.Controls[data[0]]).Text=data[1];
}
}
}
}
}
please note that this.Controls return a Control Object if you want to do any specific operations please Type Cast and then apply.
Also if you try to access
Hope that helps.

C# Text box remaining empty

I'm calling a public method from another class. It takes in a List as a parameter, and goes through the list printing out each item into a text field. The problem is the text field is remaining empty!. I've checked that the list is populated by outputing the item to the console before I put it into the text box, and the text is coming up fine there.
The list contains strings, and should output each string to the textfield followed by a semi colon.
This is the method which is being called:
public void fillAttachment(List<string> attachList)
{
for (int i = 0; i < attachList.Count; i++)
{
Console.WriteLine("List: " + attachList[i]);
txtAttach.Text += attachList[i] + ";";
}
}
I would solve it in this way:
foreach(var attach in attachList)
{
Console.WriteLine(attach);
txtAttach.AppendText(string.Format("{0};", attach));
}
Setting the text property on a text box and it not displaying could be one of the following:
You are not looking at the same control as you are setting the text in
Could you have instantiated a second copy of the form object and it is this form that you are setting the txtAttach text property in?
Could the control that you are expecting to be populated be a different one? Right click the text box that you want the text to appear in click properties and check the name.
Something else is clearing the textbox after you set it
Right click the txtAttach.Text and click Find All References, this will show you all the places that the Text property is referenced - written and read - in your project. This is a very useful way to locate other interaction with this control.
Fomatting is making the text box appear empty
Is the Font too small, or in the same colour as the background. Can you select the text in the text box?
The easiest way to test all of the above is to create a new text control on your form with a different name, change your code to populate it, check that it is indeed populated, then replace the old one.
As an aside, you could also reduce the code with a single line as follows:
public void fillAttachment(List<string> attachList)
{
txtAttach.Text = String.Join(";", attachList.ToArray());
}
Although this obviously skips out the console write line function.
Not sure why yours doesn't work but I would have done it like this...
public void fillAttachment(List<string> attachList)
{
string result = "";
//OR (if you want to append to existing textbox data)
//string result = txtAttach.Text;
for (int i = 0; i < attachList.Count; i++)
{
Console.WriteLine("List: " + attachList[i]);
result += attachList[i] + ";";
}
txtAttach.Text = result;
}
Does that work for you? If not then there is something else very wrong that is not obvious from your code

Categories