Themes and Languages Resource Dictionary - wpf

I was using the standard approach to themes in my WPF application and using a dynamicresource to change it during runtime.
This worked.
Now I have added language support (english, spanish) but when this is set, the dynamic resource no longer works for the theme. If I set the control to a static resource the theme works but then I lose the affect of changing it during runtime.
Heres the code that was added for language support but I'm confused as to why it stopped working the way I want it to.
App.xaml.cs calls this:
SetLanguage(LocalePath(CultureInfo.CurrentCulture.Name));
/// <summary>
/// Get the locale path for the resource dictionary.
/// </summary>
/// <param name="language"></param>
/// <returns></returns>
private string LocalePath(string language)
{
string file = language + ".xaml";
return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), #"Utilities\Resources\Locales\", file);
}
/// <summary>
/// Set the language using the defined resource file.
/// </summary>
/// <param name="file"></param>
private void SetLanguage(string file)
{
if (File.Exists(file))
{
var languageDictionary = new ResourceDictionary();
languageDictionary.Source = new Uri(file);
int dictionaryID = -1;
for (int i = 0; i < Resources.MergedDictionaries.Count; i++)
{
var mergedDictionary = Resources.MergedDictionaries[i];
if (mergedDictionary.Contains("ResourceDictionaryName"))
{
if (mergedDictionary["ResourceDictionaryName"].ToString().StartsWith("Locale-"))
{
dictionaryID = i;
break;
}
}
}
if (dictionaryID == -1)
{
Resources.MergedDictionaries.Add(languageDictionary);
}
else
{
Resources.MergedDictionaries[dictionaryID] = languageDictionary;
}
}
}

I had 5 other keys in the language resource dictionaries with the same key as the theme being used. Changed the key name and it works again.

Related

Setting ToolStripDropDown.DropShadowEnabled to false on multi level dropdowns

I want to disable the dropdown shadow on the dropdown of a ToolStripDropDownButton. If the dropdown menu contains items that have dropdowns themselves (e.g. multi-level menu) then setting the DropShadowEnabled to false on the ToolStripDropDownButton causes the top level dropdown to appear at the wrong position. See attached picture.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
toolStripDropDownButton1.DropDown.DropShadowEnabled = false;
}
}
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.toolStripDropDownButton1 = new System.Windows.Forms.ToolStripDropDownButton();
this.item1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.subitem1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStrip1.SuspendLayout();
this.SuspendLayout();
//
// toolStrip1
//
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripDropDownButton1});
this.toolStrip1.Location = new System.Drawing.Point(0, 0);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(292, 25);
this.toolStrip1.TabIndex = 0;
this.toolStrip1.Text = "toolStrip1";
//
// toolStripDropDownButton1
//
this.toolStripDropDownButton1.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.toolStripDropDownButton1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.item1ToolStripMenuItem});
this.toolStripDropDownButton1.Image = ((System.Drawing.Image)(resources.GetObject("toolStripDropDownButton1.Image")));
this.toolStripDropDownButton1.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolStripDropDownButton1.Name = "toolStripDropDownButton1";
this.toolStripDropDownButton1.Size = new System.Drawing.Size(29, 22);
this.toolStripDropDownButton1.Text = "toolStripDropDownButton1";
//
// item1ToolStripMenuItem
//
this.item1ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.subitem1ToolStripMenuItem});
this.item1ToolStripMenuItem.Name = "item1ToolStripMenuItem";
this.item1ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.item1ToolStripMenuItem.Text = "item1";
//
// subitem1ToolStripMenuItem
//
this.subitem1ToolStripMenuItem.Name = "subitem1ToolStripMenuItem";
this.subitem1ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.subitem1ToolStripMenuItem.Text = "subitem1";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.toolStrip1);
this.Name = "Form1";
this.Text = "Form1";
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripDropDownButton toolStripDropDownButton1;
private System.Windows.Forms.ToolStripMenuItem item1ToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem subitem1ToolStripMenuItem;
}
This is very typical lossage in the ToolStripItem classes. Clearly it is a bug, it probably got introduced when they applied a hack to work around a Windows problem. You can still see the internal bug number in the Reference Source:
public bool DropShadowEnabled {
get {
// VSWhidbey 338272 - DropShadows are only supported on TopMost windows
// due to the flakeyness of the way it's implemented in the OS. (Non toplevel
// windows can have parts of the shadow disappear because another window can get
// sandwiched between the SysShadow window and the dropdown.)
return dropShadowEnabled && TopMost && DisplayInformation.IsDropShadowEnabled;
}
set { // etc... }
}
But without a corresponding fix in the setter and the renderer.
The flakeyness they mentioned actually got fixed in Vista, you are still running on XP so you can't see it. Drop shadows are done differently on the Aero desktop and it is a system setting whether or not they are enabled. So using the property is entirely ineffective on Aero.
These ToolStripItem class bugs didn't get fixed after the .NET 2.0 release, about the entire Winforms team moved over to the WPF group. And they are certainly not getting fixed now, no point filing a bug at connect.microsoft.com although you are free to do so.
With the added wrinkle that the property just cannot have an effect anymore on later versions of Windows since it is now a system setting, the only logical thing to do here is to throw in the towel. Don't change the property.

In Silverlight, how do I find the first field bound to a model that has an error so that I can give it focus?

Greetings
I have a Silverlight form bound to a model object which implements INotifyDataErrorInfo and does validation when you click the save button. If some of the properties on the model come back invalid, Silverlight will automatically highlight the bound input field.
Is there a way to set the focus to the first invalid field?
UPDATE:
Is there even a way to see if an input field is in that invalid display state? If I can detect that, I can loop through my fields and set the focus manually.
Thanks,
Matthew
You could use a ValidationSummary in your view to display all validation errors your model raised. When you click on an error in the ValidationSummary the control which caused the validation error will be focused.
An example of the ValidationSummary can be found on the samples of the Silverlight Toolkit.
Until now I didn´t use the ValidationSummary in any application, so i cannot provide you any informations about usage or "how to use", but maybe this will help you
I've implemented this behavior.
First you need to subscribe to your ViewModel ErrorsChanged and PropertyChanged methods. I am doing this in my constructor:
/// <summary>
/// Initializes new instance of the View class.
/// </summary>
public View(ViewModel viewModel)
{
if (viewModel == null)
throw new ArgumentNullException("viewModel");
// Initialize the control
InitializeComponent(); // exception
// Set view model to data context.
DataContext = viewModel;
viewModel.PropertyChanged += new PropertyChangedEventHandler(_ViewModelPropertyChanged);
viewModel.ErrorsChanged += new EventHandler<DataErrorsChangedEventArgs>(_ViewModelErrorsChanged);
}
Then write handlers for this events:
/// <summary>
/// If model errors has changed and model still have errors set flag to true,
/// if we dont have errors - set flag to false.
/// </summary>
/// <param name="sender">Ignored.</param>
/// <param name="e">Ignored.</param>
private void _ViewModelErrorsChanged(object sender, DataErrorsChangedEventArgs e)
{
if ((this.DataContext as INotifyDataErrorInfo).HasErrors)
_hasErrorsRecentlyChanged = true;
else
_hasErrorsRecentlyChanged = false;
}
/// <summary>
/// Iterate over view model visual childrens.
/// </summary>
/// <param name="sender">Ignored.</param>
/// <param name="e">Ignored.</param>
private void _ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if ((this.DataContext as INotifyDataErrorInfo).HasErrors)
_LoopThroughControls(this);
}
And finally add method:
/// <summary>
/// If we have error and we haven't already set focus - set focus to first control with error.
/// </summary>
/// <remarks>Recursive.</remarks>
/// <param name="parent">Parent element.</param>
private void _LoopThroughControls(UIElement parent)
{
// Check that we have error and we haven't already set focus
if (!_hasErrorsRecentlyChanged)
return;
int count = VisualTreeHelper.GetChildrenCount(parent);
// VisualTreeHelper.GetChildrenCount for TabControl will always return 0, so we need to
// do this branch of code.
if (parent.GetType().Equals(typeof(TabControl)))
{
TabControl tabContainer = ((TabControl)parent);
foreach (TabItem tabItem in tabContainer.Items)
{
if (tabItem.Content == null)
continue;
_LoopThroughControls(tabItem.Content as UIElement);
}
}
// If element has childs.
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
if (child is System.Windows.Controls.Control)
{
var control = (System.Windows.Controls.Control)child;
// If control have error - we found first control, set focus to it and
// set flag to false.
if ((bool)control.GetValue(Validation.HasErrorProperty))
{
_hasErrorsRecentlyChanged = false;
control.Focus();
return;
}
}
_LoopThroughControls(child);
}
}
}

Dynamic CSV load in SQL Server

Ok so I have been searching the internet for a solution but have not yet come up with anything yet
What I have is a CSV - this CSV could have any number of unknown columns
e.g.
Col 1, Col 2, Col 3
I have used BULK INSERT #temp FROM ... to insert from a CSV but this relies on me having a table before hand to load into - This is where the problem arises - I don’t know my table structure before loading the CSV
Is there a way to dynamically create the table, based on the CSV, on the fly to load the data into?
Thanks
Rob
I was faced with the same tasks many many times. What I ended up doing is writing a simple c# script for the load. I can admit, each time I had to change the script a little bit, because each time the requirements were different, the CSV file had specific peculiarities, etc. This means that my code most likely won't work for you straight away, but I hope that it can help you a lot.
The main C# file is program.cs. Here is its source:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
namespace CsvToSql
{
class Program
{
static string server = #"localhost";
static string database = #"test";
static bool hasHeaders = false;
static string fieldLength = "max";
static string fieldPattern = "[%fieldName%] [nvarchar](%fieldLength%) NULL,\n";
static string createTablePattern =
#"
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[%tableName%]') AND type in (N'U'))
DROP TABLE [dbo].[%tableName%]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[%tableName%](
%fields%
) ON [PRIMARY]
";
static string commandScriptPattern =
#"sqlcmd -S %server% -E -d %database% -i %tableScriptName%
bcp %database%.dbo.%tableName% in %headrelsessFileName% -c -t^^ -r \n -T -S %server%
";
private static void Main(string[] args)
{
server = System.Configuration.ConfigurationSettings.AppSettings["server"] ?? server;
database = System.Configuration.ConfigurationSettings.AppSettings["database"] ?? database;
hasHeaders = System.Configuration.ConfigurationSettings.AppSettings["hasHeaders"] == "true";
fieldLength = System.Configuration.ConfigurationSettings.AppSettings["fieldLength"] ?? fieldLength;
string[] fileNames = Directory.GetFiles(".", "*.csv");
foreach (string fileName in fileNames)
{
Console.WriteLine("Processing {0}", fileName);
Process(fileName);
}
WriteExecuteAllFile(fileNames);
WriteCleanUpFile(fileNames);
}
private static void Process(string fileName)
{
string[] fieldNames = ReadHeaders(fileName);
ProduceTableScript(fileName, fieldNames);
ProduceCommandScript(fileName);
}
private static void WriteExecuteAllFile(string[] fileNames)
{
StringBuilder sb = new StringBuilder();
foreach (string fileName in fileNames)
{
sb.Append("call ");
sb.AppendLine(GetCommandScriptName(fileName));
}
SaveStringToFile(sb.ToString(), "_all.cmd");
}
private static void WriteCleanUpFile(string[] fileNames)
{
StringBuilder sb = new StringBuilder();
foreach (string fileName in fileNames)
{
sb.Append("del ");
sb.AppendLine(GetCommandScriptName(fileName));
sb.Append("del ");
sb.AppendLine(GetHeaderlessFileName(fileName));
sb.Append("del ");
sb.AppendLine(GetTableScriptName(fileName));
}
sb.AppendLine("del _all.cmd");
sb.AppendLine("del _cleanup.cmd");
SaveStringToFile(sb.ToString(), "_cleanup.cmd");
}
private static string[] ReadHeaders(string fileName)
{
using (FileStream fs = File.OpenRead(fileName))
using (StreamReader sr = new StreamReader(fs))
{
if (hasHeaders)
{
string[] result = ParseQutationLineToList(sr.ReadLine());
ProduceHeaderlessFile(sr, fs.Name);
return result;
}
else
{
string s = sr.ReadLine();
string[] fields = ParseQutationLineToList(s);
fs.Seek(0, SeekOrigin.Begin);
sr.DiscardBufferedData();
string[] result = new string[fields.Length];
for (int i = 0; i < fields.Length; i++)
{
result[i] = "F" + (i + 1).ToString();
}
ProduceHeaderlessFile(sr, fs.Name);
return result;
}
}
}
private static void ProduceTableScript(string fileName, string[] fieldNames)
{
string tableName = GetTableName(fileName);
string fields = fieldNames.Aggregate("", (s, i) => s + fieldPattern.Replace("%fieldName%", i).Replace("%fieldLength%", fieldLength));
string table = createTablePattern.Replace("%fields%", fields).Replace("%tableName%", tableName);
SaveStringToFile(table, GetTableScriptName(fileName));
}
private static void ProduceCommandScript(string fileName)
{
string content = commandScriptPattern;
content = content.Replace("%server%", server);
content = content.Replace("%database%", database);
content = content.Replace("%tableName%", GetTableName(fileName));
content = content.Replace("%tableScriptName%", GetTableScriptName(fileName));
content = content.Replace("%headrelsessFileName%", GetHeaderlessFileName(fileName));
SaveStringToFile(content, GetCommandScriptName(fileName));
}
private static void ProduceHeaderlessFile(StreamReader sr, string basefileName)
{
string headerlessFileName = GetHeaderlessFileName(basefileName);
if (File.Exists(headerlessFileName))
{
return;
}
int counter = 0;
using(FileStream fs = File.Open(headerlessFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
using (StreamWriter sw = new StreamWriter(fs))
{
while(!sr.EndOfStream)
{
//sw.WriteLine(sr.ReadLine().Replace("\"", ""));
sw.WriteLine(ParseLine(sr.ReadLine()));
counter++;
}
sw.Flush();
fs.Flush();
}
Console.WriteLine("Written {0} records to {1}", counter, headerlessFileName);
}
private static string ParseLine(string s)
{
if (s.TrimStart(' ', '\t').StartsWith("\""))
{
return ParseQutationLine(s);
}
return s.Replace(',', '^');
}
// Some tables has the default field terminator (comma) inside them
// this is why we have to parse
private static string ParseQutationLine(string s)
{
string[] fields = ParseQutationLineToList(s);
StringBuilder sb = new StringBuilder();
foreach (string field in fields)
{
sb.Append(field.Trim('"'));
sb.Append('^');
if (field.IndexOf('^') >= 0)
{
throw new ApplicationException("String contains separator character. " + s);
}
}
return sb.ToString().Substring(0, sb.Length - 1);
}
private static string[] ParseQutationLineToList(string s)
{
JouniHeikniemi.Tools.Strings.CsvReader cr = new JouniHeikniemi.Tools.Strings.CsvReader();
ArrayList result = new ArrayList();
cr.ParseCsvFields(result, s);
return (string[])result.ToArray(typeof(string));
}
private static void SaveStringToFile(string s, string fileName)
{
using (FileStream fs = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.Read))
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(s);
sw.Flush();
fs.Flush();
}
}
private static string GetTableName(string fileName)
{
return "_" + Path.GetFileNameWithoutExtension(fileName).Replace('.', '_');
}
private static string GetHeaderlessFileName(string fileName)
{
return Path.ChangeExtension(fileName, "inp");
}
private static string GetTableScriptName(string fileName)
{
return Path.ChangeExtension(fileName, "tbl");
}
private static string GetCommandScriptName(string fileName)
{
return Path.ChangeExtension(fileName, "cmd");
}
}
}
This file use a library that I found in internet for parsing CSV file. Note, that I saw valid CSV files, that this library failed to parse. The text for CsvReader.cs file follows:
using System;
using System.Collections;
using System.IO;
using System.Text;
namespace JouniHeikniemi.Tools.Strings {
/// <summary>
/// A data-reader style interface for reading Csv (and otherwise-char-separated) files.
/// </summary>
public class CsvReader : IDisposable {
#region Private variables
private Stream stream;
private StreamReader reader;
private char separator;
#endregion
#region Constructors
public CsvReader() { separator = ','; }
/// <summary>
/// Creates a new Csv reader for the given stream.
/// </summary>
/// <param name="s">The stream to read the CSV from.</param>
public CsvReader(Stream s) : this(s, null, ',') { }
/// <summary>
/// Creates a new reader for the given stream and separator.
/// </summary>
/// <param name="s">The stream to read the separator from.</param>
/// <param name="separator">The field separator character</param>
public CsvReader(Stream s, char separator) : this(s, null, separator) { }
/// <summary>
/// Creates a new Csv reader for the given stream and encoding.
/// </summary>
/// <param name="s">The stream to read the CSV from.</param>
/// <param name="enc">The encoding used.</param>
public CsvReader(Stream s, Encoding enc) : this(s, enc, ',') { }
/// <summary>
/// Creates a new reader for the given stream, encoding and separator character.
/// </summary>
/// <param name="s">The stream to read the data from.</param>
/// <param name="enc">The encoding used.</param>
/// <param name="separator">The separator character between the fields</param>
public CsvReader(Stream s, Encoding enc, char separator) {
this.separator = separator;
this.stream = s;
if (!s.CanRead) {
throw new CsvReaderException("Could not read the given data stream!");
}
reader = (enc != null) ? new StreamReader(s, enc) : new StreamReader(s);
}
/// <summary>
/// Creates a new Csv reader for the given text file path.
/// </summary>
/// <param name="filename">The name of the file to be read.</param>
public CsvReader(string filename) : this(filename, null, ',') { }
/// <summary>
/// Creates a new reader for the given text file path and separator character.
/// </summary>
/// <param name="filename">The name of the file to be read.</param>
/// <param name="separator">The field separator character</param>
public CsvReader(string filename, char separator) : this(filename, null, separator) { }
/// <summary>
/// Creates a new Csv reader for the given text file path and encoding.
/// </summary>
/// <param name="filename">The name of the file to be read.</param>
/// <param name="enc">The encoding used.</param>
public CsvReader(string filename, Encoding enc)
: this(filename, enc, ',') { }
/// <summary>
/// Creates a new reader for the given text file path, encoding and field separator.
/// </summary>
/// <param name="filename">The name of the file to be read.</param>
/// <param name="enc">The encoding used.</param>
/// <param name="separator">The field separator character.</param>
public CsvReader(string filename, Encoding enc, char separator)
: this(new FileStream(filename, FileMode.Open), enc, separator) { }
#endregion
#region Properties
/// <summary>
/// The separator character for the fields. Comma for normal CSV.
/// </summary>
public char Separator {
get { return separator; }
set { separator = value; }
}
#endregion
#region Parsing
/// <summary>
/// Returns the fields for the next row of data (or null if at eof)
/// </summary>
/// <returns>A string array of fields or null if at the end of file.</returns>
public string[] GetCsvLine() {
string data = reader.ReadLine();
if (data == null) return null;
if (data.Length == 0) return new string[0];
ArrayList result = new ArrayList();
ParseCsvFields(result, data);
return (string[])result.ToArray(typeof(string));
}
// Parses the fields and pushes the fields into the result arraylist
public void ParseCsvFields(ArrayList result, string data) {
int pos = -1;
while (pos < data.Length)
result.Add(ParseCsvField(data, ref pos));
}
// Parses the field at the given position of the data, modified pos to match
// the first unparsed position and returns the parsed field
private string ParseCsvField(string data, ref int startSeparatorPosition) {
if (startSeparatorPosition == data.Length-1) {
startSeparatorPosition++;
// The last field is empty
return "";
}
int fromPos = startSeparatorPosition + 1;
// Determine if this is a quoted field
if (data[fromPos] == '"') {
// If we're at the end of the string, let's consider this a field that
// only contains the quote
if (fromPos == data.Length-1) {
fromPos++;
return "\"";
}
// Otherwise, return a string of appropriate length with double quotes collapsed
// Note that FSQ returns data.Length if no single quote was found
int nextSingleQuote = FindSingleQuote(data, fromPos+1);
startSeparatorPosition = nextSingleQuote+1;
return data.Substring(fromPos+1, nextSingleQuote-fromPos-1).Replace("\"\"", "\"");
}
// The field ends in the next separator or EOL
int nextSeparator = data.IndexOf(separator, fromPos);
if (nextSeparator == -1) {
startSeparatorPosition = data.Length;
return data.Substring(fromPos);
}
else {
startSeparatorPosition = nextSeparator;
return data.Substring(fromPos, nextSeparator - fromPos);
}
}
// Returns the index of the next single quote mark in the string
// (starting from startFrom)
private static int FindSingleQuote(string data, int startFrom) {
int i = startFrom-1;
while (++i < data.Length)
if (data[i] == '"') {
// If this is a double quote, bypass the chars
if (i < data.Length-1 && data[i+1] == '"') {
i++;
continue;
}
else
return i;
}
// If no quote found, return the end value of i (data.Length)
return i;
}
#endregion
/// <summary>
/// Disposes the reader. The underlying stream is closed.
/// </summary>
public void Dispose() {
// Closing the reader closes the underlying stream, too
if (reader != null) reader.Close();
else if (stream != null)
stream.Close(); // In case we failed before the reader was constructed
GC.SuppressFinalize(this);
}
}
/// <summary>
/// Exception class for CsvReader exceptions.
/// </summary>
[Serializable]
public class CsvReaderException : ApplicationException {
/// <summary>
/// Constructs a new CsvReaderException.
/// </summary>
public CsvReaderException() : this("The CSV Reader encountered an error.") { }
/// <summary>
/// Constructs a new exception with the given message.
/// </summary>
/// <param name="message">The exception message.</param>
public CsvReaderException(string message) : base(message) { }
/// <summary>
/// Constructs a new exception with the given message and the inner exception.
/// </summary>
/// <param name="message">The exception message.</param>
/// <param name="inner">Inner exception that caused this issue.</param>
public CsvReaderException(string message, Exception inner) : base(message, inner) { }
/// <summary>
/// Constructs a new exception with the given serialization information.
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected CsvReaderException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
}
I also have a config file CsvToSql.exe.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="server" value="localhost"/>
<add key="database" value="test"/>
<!-- If your csv files have header, set this to true to generate field names from headers-->
<!-- Otherwise set it to false to generate names F1, F2, F3, etc.-->
<add key="hasHeaders" value="false"/>
<!-- This is the lenght of nvarchar field created can be a number or 'max'-->
<add key="fieldLength" value="500"/>
</appSettings>
</configuration>
And a script that compiles the whole lot build.cmd:
%systemroot%\Microsoft.NET\Framework\v3.5\csc.exe /out:CsvToSql.exe Program.cs CsvReader.cs
This is how I use it:
Run build.cmd to compile CsvToSql.exe
Edit CsvToSql.exe.config to fit your case
Put csv files in the same folder the executable and the config file
Run CsvToSql.exe
The executable does not connect to the database. Instead it produces a number of files:
*.tbl files are table definitions, *.inp files are input files for bcp command line utility, *.cmd files are files that run table creation scripts and bcp command line utility. _all.cmd that runs *.cmd for all tables and _cleanup.cmd that deletes all the files that CsvToSql.exe generates
Run _all.cmd file
Go to your SQL and look at what has been produced. Make changes to the script and / or config, rinse and repeat
There are a lot of assumtions that this script makes, and also a lot of stuff that is hardcoded. This is what I usaully quickly change each new time I need to load a set of CSV into SQL.
Good luck and if you have any questions please don't hesitate to ask.
The script requires .NET 3.5
If there is no extra-special about data I'm loading, I'm usually up and running with this script in 15 minutes. If there are troubles, twicking might take longer.
CSV parsing is non-trivial (taking into account text qualifiers, values that contain linebreaks, qualifier escape mechanisms, etc). There are several .Net libraries out there that do all this stuff for you (eg http://www.codeproject.com/KB/database/CsvReader.aspx), so I would think it would be easier to use a different technology, eg powershell, or SQL CLR, to make use of an existing library - rather that trying to roll your own CSV parser in T-SQL...
Huh, just found this nice and simple solution on an old forum post (http://forums.databasejournal.com/showthread.php?t=47966):
select *
from OpenRowset('MSDASQL', 'Driver={Microsoft Text Driver (*.txt; *.csv)}; DefaultDir=D:\;',
'select * from test1.csv')
Unfortunately, it doesn't work on recent windows versions where the text driver isn't installed by default...

WPF Validation: Clearing all validation errors

I have a WPF UserControl with many other controls inside of it.
TextBoxes are among these.
Every TextBox has its own validation:
<TextBox>
<TextBox.Text>
<Binding Path="MyPath" StringFormat="{}{0:N}" NotifyOnValidationError="True">
<Binding.ValidationRules>
<r:MyValidationRule ValidationType="decimal" />
</Binding.ValidationRules>
</Binding>
<TextBox.Text>
<TextBox>
a
Now suppose the user types some invalid characters into them. They will all become highlighted red.
Now I want to reset all the validation errors (from the incorrect input) and set the recent correct values coming from DataContext.
I set the DataContext in the constructor and I don't want to change it (DataContext = null won't help me then):
DataContext = _myDataContext = new MyDataContext(..);
What I've already found are these classes:
Validation.ClearInvalid(..)
BindingExpression.UpdateTarget();
I think these classes could help me, but they require the Binding of a concrete FrameworkElement and I want to do it globally for all of them.
Should I anyhow iterate through the Visual Tree (which is really what I don't like) or is there any better solution for this?
This is what a BindingGroup is for... You'd set a BindingGroup on a container of all the controls, e.g. the panel that contains them. This would cause the updates to the DataContext to be held until you call UpdateSources on the BindingGroup. If you want to reset the user's input, you'd call CancelEdit instead, and the BindingGroup would reset all controls inside the container to the (still unchanged) values of the DataContext.
I had the same problem. Multiple validated controls on a page. I found/made this solution to update (and clear all validation from) the descentents of a DependencyObject:
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
/// <summary>
/// Updates all binding targets where the data item is of the specified type.
/// </summary>
/// <param name="root">The root.</param>
/// <param name="depth">The depth.</param>
/// <param name="dataItemType">Type of the data item.</param>
/// <param name="clearInvalid">Clear validation errors from binding.</param>
public static void UpdateAllBindingTargets(this DependencyObject root, int depth, Type dataItemType, bool clearInvalid)
{
var bindingExpressions = EnumerateDescendentsBindingExpressions(root, depth);
foreach (BindingExpression be in bindingExpressions.Where(be => be.DataItem != null && be.DataItem.GetType() == dataItemType))
{
if (be != null)
{
be.UpdateTarget();
if (clearInvalid)
System.Windows.Controls.Validation.ClearInvalid(be);
}
}
}
/// <summary>
/// Enumerates all binding expressions on descendents.
/// </summary>
/// <param name="root">The root.</param>
/// <param name="depth">The depth.</param>
/// <returns></returns>
public static IEnumerable<BindingExpression> EnumerateDescendentsBindingExpressions(this DependencyObject root, int depth)
{
return root.EnumerateDescendents(depth).SelectMany(obj => obj.EnumerateBindingExpressions());
}
/// <summary>
/// Enumerates the descendents of the specified root to the specified depth.
/// </summary>
/// <param name="root">The root.</param>
/// <param name="depth">The depth.</param>
public static IEnumerable<DependencyObject> EnumerateDescendents(this DependencyObject root, int depth)
{
int count = VisualTreeHelper.GetChildrenCount(root);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(root, i);
yield return child;
if (depth > 0)
{
foreach (var descendent in EnumerateDescendents(child, --depth))
yield return descendent;
}
}
}
/// <summary>
/// Enumerates the binding expressions of a Dependency Object.
/// </summary>
/// <param name="element">The parent element.</param>
public static IEnumerable<BindingExpression> EnumerateBindingExpressions(this DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
LocalValueEnumerator lve = element.GetLocalValueEnumerator();
while (lve.MoveNext())
{
LocalValueEntry entry = lve.Current;
if (BindingOperations.IsDataBound(element, entry.Property))
{
if (entry.Value is PriorityBindingExpression)
{
foreach (BindingExpression expr in ((PriorityBindingExpression)entry.Value).BindingExpressions)
yield return expr;
}
else if (entry.Value is MultiBindingExpression)
{
foreach (BindingExpression expr in ((MultiBindingExpression)entry.Value).BindingExpressions)
yield return expr;
}
else
yield return entry.Value as BindingExpression;
}
}
}
Why won't you just trigger NotifyPropertyChanged for all the properties of your data source? This will update binding and UI controls should get values from datacontext (which are valid, thus validation errors will be cleared)?
I'm not sure what you mean by
I set the DataContext in the constructor and I don't want to change it
(DataContext = null won't help me then)
Generally to reset all bindings on the form you do the following: (assuming a controller for views/viewmodel wiring, otherwise just use a code-behind on the view.)
var dataContext = view.DataContext;
view.DataContext = null;
view.DataContext = dataContext;
It doesn't change it to a new data context, it just drops the data context and reloads it. This kicks off all of the bindings to re-load.
Although hbarck gave a perfectly correct answer, I would just like to add that for many standard WPF controls, BindingGroups are created automatically. Therefore, in most cases, the following simple code is enough for clearing all validation errors inside some control (for example, DataGrid):
foreach (var bg in BindingOperations.GetSourceUpdatingBindingGroups(myDataGrid))
bg.CancelEdit();

Formatting text in WinForm Label

Is it possible to format certain text in a WinForm Label instead of breaking the text into multiple labels? Please disregard the HTML tags within the label's text; it's only used to get my point out.
For example:
Dim myLabel As New Label
myLabel.Text = "This is <b>bold</b> text. This is <i>italicized</i> text."
Which would produce the text in the label as:
This is bold text. This is
italicized text.
That's not possible with a WinForms label as it is. The label has to have exactly one font, with exactly one size and one face. You have a couple of options:
Use separate labels
Create a new Control-derived class that does its own drawing via GDI+ and use that instead of Label; this is probably your best option, as it gives you complete control over how to instruct the control to format its text
Use a third-party label control that will let you insert HTML snippets (there are a bunch - check CodeProject); this would be someone else's implementation of #2.
Not really, but you could fake it with a read-only RichTextBox without borders. RichTextBox supports Rich Text Format (rtf).
Another workaround, late to the party: if you don't want to use a third party control, and you're just looking to call attention to some of the text in your label, and you're ok with underlines, you can use a LinkLabel.
Note that many consider this a 'usability crime', but if you're not designing something for end user consumption then it may be something you're prepared to have on your conscience.
The trick is to add disabled links to the parts of your text that you want underlined, and then globally set the link colors to match the rest of the label. You can set almost all the necessary properties at design-time apart from the Links.Add() piece, but here they are in code:
linkLabel1.Text = "You are accessing a government system, and all activity " +
"will be logged. If you do not wish to continue, log out now.";
linkLabel1.AutoSize = false;
linkLabel1.Size = new Size(365, 50);
linkLabel1.TextAlign = ContentAlignment.MiddleCenter;
linkLabel1.Links.Clear();
linkLabel1.Links.Add(20, 17).Enabled = false; // "government system"
linkLabel1.Links.Add(105, 11).Enabled = false; // "log out now"
linkLabel1.LinkColor = linkLabel1.ForeColor;
linkLabel1.DisabledLinkColor = linkLabel1.ForeColor;
Result:
Worked solution for me - using custom RichEditBox. With right properties it will be looked as simple label with bold support.
1) First, add your custom RichTextLabel class with disabled caret :
public class RichTextLabel : RichTextBox
{
public RichTextLabel()
{
base.ReadOnly = true;
base.BorderStyle = BorderStyle.None;
base.TabStop = false;
base.SetStyle(ControlStyles.Selectable, false);
base.SetStyle(ControlStyles.UserMouse, true);
base.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
base.MouseEnter += delegate(object sender, EventArgs e)
{
this.Cursor = Cursors.Default;
};
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x204) return; // WM_RBUTTONDOWN
if (m.Msg == 0x205) return; // WM_RBUTTONUP
base.WndProc(ref m);
}
}
2) Split you sentence to words with IsSelected flag, that determine if that word should be bold or no :
private void AutocompleteItemControl_Load(object sender, EventArgs e)
{
RichTextLabel rtl = new RichTextLabel();
rtl.Font = new Font("MS Reference Sans Serif", 15.57F);
StringBuilder sb = new StringBuilder();
sb.Append(#"{\rtf1\ansi ");
foreach (var wordPart in wordParts)
{
if (wordPart.IsSelected)
{
sb.Append(#"\b ");
}
sb.Append(ConvertString2RTF(wordPart.WordPart));
if (wordPart.IsSelected)
{
sb.Append(#"\b0 ");
}
}
sb.Append(#"}");
rtl.Rtf = sb.ToString();
rtl.Width = this.Width;
this.Controls.Add(rtl);
}
3) Add function for convert you text to valid rtf (with unicode support!) :
private string ConvertString2RTF(string input)
{
//first take care of special RTF chars
StringBuilder backslashed = new StringBuilder(input);
backslashed.Replace(#"\", #"\\");
backslashed.Replace(#"{", #"\{");
backslashed.Replace(#"}", #"\}");
//then convert the string char by char
StringBuilder sb = new StringBuilder();
foreach (char character in backslashed.ToString())
{
if (character <= 0x7f)
sb.Append(character);
else
sb.Append("\\u" + Convert.ToUInt32(character) + "?");
}
return sb.ToString();
}
Works like a charm for me!
Solutions compiled from :
How to convert a string to RTF in C#?
Format text in Rich Text Box
How to hide the caret in a RichTextBox?
Create the text as a RTF file in wordpad
Create Rich text control with no borders and editable = false
Add the RTF file to the project as a resource
In the Form1_load do
myRtfControl.Rtf = Resource1.MyRtfControlText
AutoRichLabel
I was solving this problem by building an UserControl that contains a TransparentRichTextBox that is readonly. The TransparentRichTextBox is a RichTextBox that allows to be transparent:
TransparentRichTextBox.cs:
public class TransparentRichTextBox : RichTextBox
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern IntPtr LoadLibrary(string lpFileName);
protected override CreateParams CreateParams
{
get
{
CreateParams prams = base.CreateParams;
if (TransparentRichTextBox.LoadLibrary("msftedit.dll") != IntPtr.Zero)
{
prams.ExStyle |= 0x020; // transparent
prams.ClassName = "RICHEDIT50W";
}
return prams;
}
}
}
The final UserControl acts as wrapper of the TransparentRichTextBox. Unfortunately, I had to limit it to AutoSize on my own way, because the AutoSize of the RichTextBox became broken.
AutoRichLabel.designer.cs:
partial class AutoRichLabel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.rtb = new TransparentRichTextBox();
this.SuspendLayout();
//
// rtb
//
this.rtb.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.rtb.Dock = System.Windows.Forms.DockStyle.Fill;
this.rtb.Location = new System.Drawing.Point(0, 0);
this.rtb.Margin = new System.Windows.Forms.Padding(0);
this.rtb.Name = "rtb";
this.rtb.ReadOnly = true;
this.rtb.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
this.rtb.Size = new System.Drawing.Size(46, 30);
this.rtb.TabIndex = 0;
this.rtb.Text = "";
this.rtb.WordWrap = false;
this.rtb.ContentsResized += new System.Windows.Forms.ContentsResizedEventHandler(this.rtb_ContentsResized);
//
// AutoRichLabel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.BackColor = System.Drawing.Color.Transparent;
this.Controls.Add(this.rtb);
this.Name = "AutoRichLabel";
this.Size = new System.Drawing.Size(46, 30);
this.ResumeLayout(false);
}
#endregion
private TransparentRichTextBox rtb;
}
AutoRichLabel.cs:
/// <summary>
/// <para>An auto sized label with the ability to display text with formattings by using the Rich Text Format.</para>
/// <para>­</para>
/// <para>Short RTF syntax examples: </para>
/// <para>­</para>
/// <para>Paragraph: </para>
/// <para>{\pard This is a paragraph!\par}</para>
/// <para>­</para>
/// <para>Bold / Italic / Underline: </para>
/// <para>\b bold text\b0</para>
/// <para>\i italic text\i0</para>
/// <para>\ul underline text\ul0</para>
/// <para>­</para>
/// <para>Alternate color using color table: </para>
/// <para>{\colortbl ;\red0\green77\blue187;}{\pard The word \cf1 fish\cf0 is blue.\par</para>
/// <para>­</para>
/// <para>Additional information: </para>
/// <para>Always wrap every text in a paragraph. </para>
/// <para>Different tags can be stacked (i.e. \pard\b\i Bold and Italic\i0\b0\par)</para>
/// <para>The space behind a tag is ignored. So if you need a space behind it, insert two spaces (i.e. \pard The word \bBOLD\0 is bold.\par)</para>
/// <para>Full specification: http://www.biblioscape.com/rtf15_spec.htm </para>
/// </summary>
public partial class AutoRichLabel : UserControl
{
/// <summary>
/// The rich text content.
/// <para>­</para>
/// <para>Short RTF syntax examples: </para>
/// <para>­</para>
/// <para>Paragraph: </para>
/// <para>{\pard This is a paragraph!\par}</para>
/// <para>­</para>
/// <para>Bold / Italic / Underline: </para>
/// <para>\b bold text\b0</para>
/// <para>\i italic text\i0</para>
/// <para>\ul underline text\ul0</para>
/// <para>­</para>
/// <para>Alternate color using color table: </para>
/// <para>{\colortbl ;\red0\green77\blue187;}{\pard The word \cf1 fish\cf0 is blue.\par</para>
/// <para>­</para>
/// <para>Additional information: </para>
/// <para>Always wrap every text in a paragraph. </para>
/// <para>Different tags can be stacked (i.e. \pard\b\i Bold and Italic\i0\b0\par)</para>
/// <para>The space behind a tag is ignored. So if you need a space behind it, insert two spaces (i.e. \pard The word \bBOLD\0 is bold.\par)</para>
/// <para>Full specification: http://www.biblioscape.com/rtf15_spec.htm </para>
/// </summary>
[Browsable(true)]
public string RtfContent
{
get
{
return this.rtb.Rtf;
}
set
{
this.rtb.WordWrap = false; // to prevent any display bugs, word wrap must be off while changing the rich text content.
this.rtb.Rtf = value.StartsWith(#"{\rtf1") ? value : #"{\rtf1" + value + "}"; // Setting the rich text content will trigger the ContentsResized event.
this.Fit(); // Override width and height.
this.rtb.WordWrap = this.WordWrap; // Set the word wrap back.
}
}
/// <summary>
/// Dynamic width of the control.
/// </summary>
[Browsable(false)]
public new int Width
{
get
{
return base.Width;
}
}
/// <summary>
/// Dynamic height of the control.
/// </summary>
[Browsable(false)]
public new int Height
{
get
{
return base.Height;
}
}
/// <summary>
/// The measured width based on the content.
/// </summary>
public int DesiredWidth { get; private set; }
/// <summary>
/// The measured height based on the content.
/// </summary>
public int DesiredHeight { get; private set; }
/// <summary>
/// Determines the text will be word wrapped. This is true, when the maximum size has been set.
/// </summary>
public bool WordWrap { get; private set; }
/// <summary>
/// Constructor.
/// </summary>
public AutoRichLabel()
{
InitializeComponent();
}
/// <summary>
/// Overrides the width and height with the measured width and height
/// </summary>
public void Fit()
{
base.Width = this.DesiredWidth;
base.Height = this.DesiredHeight;
}
/// <summary>
/// Will be called when the rich text content of the control changes.
/// </summary>
private void rtb_ContentsResized(object sender, ContentsResizedEventArgs e)
{
this.AutoSize = false; // Disable auto size, else it will break everything
this.WordWrap = this.MaximumSize.Width > 0; // Enable word wrap when the maximum width has been set.
this.DesiredWidth = this.rtb.WordWrap ? this.MaximumSize.Width : e.NewRectangle.Width; // Measure width.
this.DesiredHeight = this.MaximumSize.Height > 0 && this.MaximumSize.Height < e.NewRectangle.Height ? this.MaximumSize.Height : e.NewRectangle.Height; // Measure height.
this.Fit(); // Override width and height.
}
}
The syntax of the rich text format is quite simple:
Paragraph:
{\pard This is a paragraph!\par}
Bold / Italic / Underline text:
\b bold text\b0
\i italic text\i0
\ul underline text\ul0
Alternate color using color table:
{\colortbl ;\red0\green77\blue187;}
{\pard The word \cf1 fish\cf0 is blue.\par
But please note: Always wrap every text in a paragraph. Also, different tags can be stacked (i.e. \pard\b\i Bold and Italic\i0\b0\par) and the space character behind a tag is ignored. So if you need a space behind it, insert two spaces (i.e. \pard The word \bBOLD\0 is bold.\par). To escape \ or { or }, please use a leading \.
For more information there is a full specification of the rich text format online.
Using this quite simple syntax you can produce something like you can see in the first image. The rich text content that was attached to the RtfContent property of my AutoRichLabel in the first image was:
{\colortbl ;\red0\green77\blue187;}
{\pard\b BOLD\b0 \i ITALIC\i0 \ul UNDERLINE\ul0 \\\{\}\par}
{\pard\cf1\b BOLD\b0 \i ITALIC\i0 \ul UNDERLINE\ul0\cf0 \\\{\}\par}
If you want to enable word wrap, please set the maximum width to a desired size. However, this will fix the width to the maximum width, even when the text is shorter.
Have fun!
There is an excellent article from 2009 on Code Project named "A Professional HTML Renderer You Will Use" which implements something similar to what the original poster wants.
I use it successfully within several projects of us.
Very simple solution:
Add 2 labels on the form, LabelA and LabelB
Go to properties for LabelA and dock it to left.
Go to properties for LabelB and dock it to left as well.
Set Font to bold for LabelA .
Now the LabelB will shift depending on length of text of LabelA.
That's all.
I Would also be interested in finding out if it is possible.
When we couldn't find a solution we resorted to Component Ones 'SuperLabel' control which allows HTML markup in a label.
Realising this is an old question, my answer is more for those, like me, who still may be looking for such solutions and stumble upon this question.
Apart from what was already mentioned, DevExpress's LabelControl is a label that supports this behaviour - demo here. Alas, it is part of a paid library.
If you're looking for free solutions, I believe HTML Renderer is the next best thing.
A FlowLayoutPanel works well for your problem. If you add labels to the flow panel and format each label's font and margin properties, then you can have different font styles. Pretty quick and easy solution to get working.
Yeah.
You can implements, using HTML Render.
For you see, click on the link: https://htmlrenderer.codeplex.com/
I hope this is useful.

Resources