Epplus - checking if named style already exists before adding it - c#

I have a class Comparer, which defines the following:
// partial Comparer code
public class Comparer
{
private readonly Color colorWarning = Color.Red;
private readonly string SPREADSHEET_RED_WARNING_STYLE = "red warning style";
private OfficeOpenXml.Style.XmlAccess.ExcelNamedStyle redWarningStyle;
}
This class has a method prepareSpreadsheet:
private void prepareSpreadsheet()
{
// spreadsheet styles
redWarningStyle = spreadsheet.Workbook.Styles.CreateNamedStyle(SPREADSHEET_RED_WARNING_STYLE);
redWarningStyle.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
redWarningStyle.Style.Fill.BackgroundColor.SetColor(colorWarning);
redWarningStyle.Style.Font.Color.SetColor(Color.Black)
}
If the spreadsheet file already contains such a named style, an exception is thrown. Can Epplus programatically check if a certain named style already exists in the spreadsheet, and remove it if it does?

I have managed to get it working, but not sure if it is the best solution. It does not remove them, only adds if it finds a style with an existing name (cannot guarantee it has the same style):
// retrieve a list of styles from the spreadsheet
List<OfficeOpenXml.Style.XmlAccess.ExcelNamedStyleXml> spreadsheetNamedStyles = spreadsheet.Workbook.Styles.NamedStyles.ToList();
// check if it already exists before attempting to add it
if (spreadsheetNamedStyles.FirstOrDefault(namedStyle => namedStyle.Name.Equals(SPREADSHEET_RED_WARNING_STYLE)) == null)
{
redWarningStyle = spreadsheet.Workbook.Styles.CreateNamedStyle(SPREADSHEET_RED_WARNING_STYLE);
redWarningStyle.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
redWarningStyle.Style.Fill.BackgroundColor.SetColor(colorWarning);
redWarningStyle.Style.Font.Color.SetColor(Color.Black);
}

Related

How set a variable the Properties.Settings.Default?

I have two Properties files that store colors.
Properties.Green.Theme
Properties.PurpleTheme
The names of the parameters in the files are completely the same. I want to implement a theme change by switching between these two files. The simplest thing, in theory, is to assign a variable a value with a visibility level for the entire class. For example, var theme = Properties.GreenTheme.Default. And then use this variable in the methods. because the names are the same everywhere. Sample code in what form I want to do it:
public partial class FrmMain : Form{
TypeVar theme = null;
public FrmMain()
{
InitializeComponent();
if (i = 1)
{
theme = Properties.GreenTheme.Default;
}
if (i = 3)
{
theme = Properties.PurpleTheme.Default;
}
SetBottonColor();
SetPanelColor();
}
private void SetBottonColor()
{
btn.BackColor = theme.button_color;
btn2.BackColor = theme.button_color;
btn3.BackColor = theme.button_color;
}
private void SetPanelColor()
{
panel.BackColor = theme.panel_color;
panel2.BackColor = theme.panel_color;
}
}
that is, in order not to prescribe if in each method, I want to create a variable at the class level and change it when loading the form. And since the names of the parameters in the files are the same, the colors would be taken from the desired file. Locally I can easily declare a variable
var theme = Properties.PurpleTheme.Default;
But I need it at the class level because there are a lot of such methods. object as var unfortunately does not work...
p.s. Sorry for my English

How to calculate selected Excel range using ExcelDnaUtil.Application selection?

I'm writing a custom Excel add-in that assigns specific keyboard shortcuts to tasks such as number formatting for selected cells only. When I try to add a shortcut that will recalculate the selected range only, the entire sheet is re-calculated.
public class Main : IExcelAddIn
{
public void AutoOpen()
{
dynamic app = ExcelDnaUtil.Application;
app.OnKey("^N", "FormatNumbers");
app.OnKey("^C", "CalcSelection");
}
public void AutoClose()
{
}
}
public class KeyboardShortcuts
{
public static void FormatNumbers()
{
dynamic app = ExcelDnaUtil.Application;
dynamic selection = app.Selection;
selection.NumberFormat = "#,##0;[Red]-#,##0";
}
public static void CalcSelection()
{
dynamic app = ExcelDnaUtil.Application;
dynamic selection = app.Selection;
selection.Calculate();
}
}
The FormatNumbers method works perfectly but the CalcSelection method forces the entire sheet to be recalculated rather than just the bits I've selected.
Would appreciate any suggestions to make this code work?
There are various quirks related to the Excel Range.Calculate call. You can find some good information on the FastExcel site from Charles Williams: https://www.decisionmodels.com/calcsecretsg.htm
If the book is in automatic calculation mode, it sounds like Range.Calculate will recalculate all volatile cells on all worksheets.

How to set text to a control from resource file in design time?

I want to know if there exists a way to set a control's Text property from a resource file in design time:
Or this process can only be performed programatically?
The designer only serializes string for Text property. You can not set the Text property to a resource value directly using designer.
Even if you open the Form1.Designer.cs file and add a line to initialization to set the Text property to a resource value like Resource1.Key1, after first change in designer, the designer replace your code by setting the string value of that resource for Text property.
In general I recommend using standard localization mechanisms of windows forms, using Localizable and Language property of Form.
But if in some reason you want to use your resource file and want to use a designer-based solution, as good option you can create an extender component to set the resource key for your control at design-time and then use it at run-time.
Code for the extender component is at the end of the post.
Usage
Make sure you have a resource file. For example Resources.resx in the properties folder. Also make sure you have some resource key/value in the resource file. For example Key1 with value = "Value1", Key2 with value = "Value2". Then:
Put a ControlTextExtender component on your form.
Using property grid set the ResourceClassName property of it to the full name of your resource file for example WindowsApplication1.Properties.Resources`
Select each control you want to set its Text and using property grid set the value of ResourceKey on controlTextExtender1 property to the resource key that you want.
Then run the application and see the result.
Result
and here is an screenshot of result, and as you see, I even localized Text property of the form this way.
Switch between Cultures at Run-Time
You can switch between cultures at run-time, without need to close and reopen the form simply using:
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fa");
this.controlTextExtender1.EndInit();
Implementation
Here is a basic implementation of the idea:
[ProvideProperty("ResourceKey", typeof(Control))]
public class ControlTextExtender
: Component, System.ComponentModel.IExtenderProvider, ISupportInitialize
{
private Hashtable Controls;
public ControlTextExtender() : base() { Controls = new Hashtable(); }
[Description("Full name of resource class, like YourAppNamespace.Resource1")]
public string ResourceClassName { get; set; }
public bool CanExtend(object extendee)
{
if (extendee is Control)
return true;
return false;
}
public string GetResourceKey(Control control)
{
return Controls[control] as string;
}
public void SetResourceKey(Control control, string key)
{
if (string.IsNullOrEmpty(key))
Controls.Remove(control);
else
Controls[control] = key;
}
public void BeginInit() { }
public void EndInit()
{
if (DesignMode)
return;
var resourceManage = new ResourceManager(this.ResourceClassName,
this.GetType().Assembly);
foreach (Control control in Controls.Keys)
{
string value = resourceManage.GetString(Controls[control] as string);
control.Text = value;
}
}
}

CodedUI search for grandchild control?

I have a table which has multiple rows. I want to verify that a specific string StringName is in the table. I used CodedUI to find the control, and the UI map is like this:
public class UIItemTable : WpfTable
{
#region Fields
private UIItemRow mUIItemRow;
#endregion
}
public class UIItemRow : WpfRow
{
#region Fields
private UIBlahBlahBlahCell mUIBlahBlahBlahCell;
#endregion
}
public class UIBlahBlahBlahCell : WpfCell
{
#region Fields
private WpfText mUIBlahBlahBlahText;
#endregion
}
I want to find a WpfText that matches my StringName. So I added a function to UIItemTable:
public class UIItemTable : WpfTable
{
public WpfText Find(string StringName)
{
WpfText StringNameWpfText = new WpfText(this);
StringNameWpfText.SearchProperties[WpfText.PropertyNames.Name] = StringName;
return StringNameWpfText;
}
#region Fields
private UIItemRow mUIItemRow;
#endregion
}
But CodedUI cannot find the WpfText control. The error I received is:
Microsoft.VisualStudio.TestTools.UITest.Extension.UITestControlNotFoundException.
The playback failed to find the control with the given search
properties. Additional Details: TechnologyName: 'UIA' ControlType:
'Text' Name: ...
I think this error may be due to the fact that the WpfCell I want to search is actually a grandchild of the table. But I thought CodedUI handles tree traversals right? How do I search for a grandchild?
You should move your code out of the partial UIMap.designer.cs class as it will be overwritten the next time you record a control/assert/etc. Move you code to the uimap.cs partial class instead.
The text control may or may not be the next level down, if it is not on the child level of UIItemTable, your code will fail. You should try to use the test tool builder cross hair to identify the level it exists at.
You can use the child enumerator and search through all child/grandchild/etc elements until you find your text item, an example below would be something like:
public UIControl FindText(UIControl ui)
{
UIControl returnControl = null;
IEnumerator<UITestControl> UIItemTableChildEnumerator =
ui.GetChildren().GetEnumerator();
while(uiChildEnumerator.MoveNext())
{
if(uiChildEnumerator.Current.DisplayText.equals(StringName))
{
returnControl = uiChildEnumerator.Current
break;
}
else
{
returnControl = this.FindText(uiChildEnumerator.Current)
if(returnControl != null)
{
break;
}
}
}
return returnControl;
}
4 . Another option would be to use the FindMatchingControls() function and parse through similar to the above statement. You might still need the proper direct parents though
WpfText StringNameWpfText = new WpfText(this);
IEnumerator<UITestControl> textItems = StringNameWpfText .FindMatchingControls().GetEnumerator();
while (textItems.MoveNext())
{
//search
}
Hope this helps
I usually find cells first. I believe any content in a table would be in a cell. So we can search for the cells first and then dive in it.
One way to find cell whose value matches with the given string.
WpfCell cell = myWpfTable.FindFirstCellWithValue(string StringName);
if(cell != null)
return cell.Value // returns WpfControl;
else
return null;
Another way to get the value of cell which contains a particular string
WpfCell myCell = myWpfTable.Cells
.FirstOrDefault(c => c.Value.Contains("StringName"));
var myTextControl = myCell != null ? myCell.Value : null;
If the text is nested deep in the cell, then you can do this. Just like what you were doing with the table
// Find cell which contains the particular string, let say it "myCell"
WpfText mytext = new WpfText(myCell);
mytext.SearchProperties.Add(WpfText.PropertyNames.Name, "StringName", PropertyExpressionOperator.Contains);
if(mytext.Exist)
return myText;
else
retrun null;

CheckedListBox - Collection of FileInfo objects - Display Custom ToString

I have a CheckedListBox in a WinForms app (3.5 runtime), and I am adding a bunch of FileInfo objects to the Items ObjectCollection. The problem is that I don't like what is displayed in the CheckedListBox (since the FileInfo was from a Directory.GetFiles() it just shows the FileInfo.Name of the file in the listbox).
Is there any easy way to change what is displayed in the CheckedListBox without having to create a seperate custom class/object.
I am basically doing
checkedListBox.Items.Add(fileInfo)
and the result is just the file name of the file.
Changing display member works but I can't create something custom, only the existing properties in the FileInfo class.
I want to be able to display something like Name - FullName
Example (desired):
File1.txt - C:\Path\SubPath\File1.txt
Actually, it seems like it should be possible after all. The CheckedListBox has a FormattingEnabled property and a Format event inherited from ListBox which is called before each item is displayed. So something along these lines should work:
myCheckedListBox.FormattingEnabled = true;
myCheckedListBox.Format += (s, e) => { e.Value = string.Format("{0} - {1}", ((FileInfo)e.ListItem).Name, ((FileInfo)e.ListItem).FullName); };
Haven't tested it though. See also MSDN
Old answer:
I don't think you can do it without creating a wrapper. Although 10 lines of code don't seem all that bad to me:
class FileInfoView
{
public FileInfo Info { get; private set; }
public FileInfoView(FileInfo info)
{
Info = info;
}
public override string ToString()
{
// return whatever you want here
}
}
The additional advantage to having a view model is that you can decorate it further for display purposes all the way you like.
I dont know if there is work around for this except creating a custom class and include an instance of FileInfo inside it
and in this way you either create a new property and include a custom data in it or override the ToString() function
something like (this for demonstration purposes)
MyFileInfo
{
public FileInfo TheFileInfo;
public string CustomProperty
{
get
{
if(this.TheFileInfo != null)
return this.TheFileInfo.FileName + this.TheFileInfo.FullName;
return string.Empty;
}
}
}

Categories