My name is Edward Tanguay. I'm an American software and web developer living and working in Berlin, Germany.


22 hours ago: More effective way to display percentages of a whole than with a pie chart, BBC's budget infographic: http://bit.ly/bOORuZ.
22 hours ago: Good colin marshall podcast interviewing Ian Ayres on coming importance of supercrunching and statistics: http://bit.ly/bPOT6s.
23 hours ago: This sandribbon for silverlight demo is amazing, resize your browser, it's like office 2007 in your browser: http://bit.ly/9mXJWN.
3 days ago: 01:00:00 sunday run, five hard insulaner hills, went from 7C to 2C as sun went down, still snow on hill: http://tanguay.info/run.
3 days ago: PHP still has one up on C#: you can do this: $html = '<div class="main">';.
4 days ago: C# CODE EXAMPLE: How to use NameValueCollection for a collection of items with both single and multiple keys: http://bit.ly/blPvIL.
5 days ago: Very informative podcast on copyright law in software/music business, brad frazer eloquent and knowledgable on topic: http://bit.ly/dxwfcF.
5 days ago: C# CODE EXAMPLE: How to use TryGetValue with Dictionary to test and get value if exists in one statement: http://bit.ly/cAIerG.
6 days ago: Search got much better in thunderbird 3, lots of choices, like it: http://bit.ly/cvJcg3.
6 days ago: 01:00:00 after work run, freezing cold but clear night with stars, no ice or snow: http://tanguay.info/run.
6 days ago: C# CODE EXAMPLE: How to overload constructors with the "this" keyword: http://bit.ly/bKBKHA.
How to use NameValueCollection for a collection of items with both single and multiple keys I needed a collection type to easily lookup values with multiple, identical keys and since I was just storing strings, the non-generic NameValueCollection was exactly what I needed, here's an example of what it can do. This example assumes you know which keys are singular and multiple in your collection. Note that if you use .Get() on a multiple key, it will nicely return a comma-delimited string. ![]()
using System; using System.Linq; using System.Text; using System.Collections.Specialized; namespace TestMultipleKeyDictionary8282 { public class Program { static void Main(string[] args) { NameValueCollection variables = new NameValueCollection(); variables.Add("title", "Report #3"); variables.Add("description", "This is the description."); variables.Add("note", "more information is available from marketing"); variables.Add("note", "time limit for this project is 18 hours"); variables.Add("todo", "expand the outline"); variables.Add("todo", "work on the introduction"); variables.Add("todo", "lookup footnotes"); string[] singleVariableNames = { "title", "subtitle", "description", "author", "datePublished" }; string[] multipleVariableNames = { "note", "todo", "info" }; foreach (var singleVariableName in singleVariableNames) { if (variables.Get(singleVariableName) != null) Console.WriteLine("{0,-15} {1}", singleVariableName, variables.Get(singleVariableName)); else Console.WriteLine("{0,-15} {1}", singleVariableName, "N/A"); } foreach (var multipleVariableName in multipleVariableNames) { if (variables.Get(multipleVariableName) != null) variables.GetValues(multipleVariableName).ToList().ForEach(v => Console.WriteLine("{0,-15} {1}", multipleVariableName, v)); else Console.WriteLine("{0,-15} {1}", multipleVariableName, "N/A"); } ShowEntries(variables); variables.Remove("todo"); ShowEntries(variables); variables.Clear(); ShowEntries(variables); Console.ReadLine(); } public static void ShowEntries(NameValueCollection nvc) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < nvc.Keys.Count; i++) { sb.Append(nvc.Keys[i] + ", "); } Console.WriteLine("There are {0} kinds of keys: {1}", nvc.Count, sb.ToString().TrimEnd(new char[] {',',' '})); } } } |
How to use TryGetValue with Dictionary to test and get value if exists in one statement The TryGetValue method of Dictionary allows you to test if a key exists in the dictionary and if so, return the value, which makes for code that reads nicely. ![]()
using System;
using System.Collections.Generic; namespace TestDictionary882282 { class Program { static void Main(string[] args) { Dictionary<int, string> variableNames = new Dictionary<int, string>(); variableNames.Add(3, "first"); variableNames.Add(7, "second"); variableNames.Add(21, "third"); variableNames.Add(22, "fourth"); variableNames.Add(24, "fifth"); int[] keys = { 3, 7, 22, 23, 24, 25 }; string variableName = ""; foreach (var key in keys) { if(variableNames.TryGetValue(key, out variableName)) Console.WriteLine("key {0} equals {1}", key, variableName); else Console.WriteLine("KEY {0} DOES NOT EXIST", key); } Console.ReadLine(); } } } |
How to overload constructors with the "this" keyword Just as you can use the "base" keyword to call constructors in inherited classes, you can use the "this" keyword to overload constructors in the same class. ![]()
using System; namespace TestConstruct23843 { class Program { static void Main(string[] args) { Customer customer1 = new Customer("Joe", "Black"); Customer customer2 = new Customer("Jim"); Console.WriteLine("{0} {1}", customer1.FirstName, customer1.LastName); Console.WriteLine("{0} {1}", customer2.FirstName, customer2.LastName); Console.ReadLine(); } } public class Customer { public string FirstName { get; set; } public string LastName { get; set; } public Customer(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } public Customer(string firstName) : this(firstName, "(unknown)") { } } } |
How to make a CSS layout for icon-left, text-right with floating divs One of the only ways to get an image-left / text-right layout to work in HTML when you have various-sized images is to use HTML tables. However, if you are generating your code with a script and you know the width of your images (or if all of your images are the same width), you can use this floating-div solution. Note that in this example I have to use in-line styles to indicate the width of each icon image, but if you need to avoid tables, this is nice solution. ![]() > > > Download Code > > > View Demo
<html> <style> * { margin: 0; padding: 0 } body { padding: 20px; text-align: center; background-color: #333; } p { margin: 0 0 10px 0; } #content { width: 600px; margin-left: auto; margin-right: auto; background: brown; border: 1px solid #555; text-align: left; } .item { margin: 20px; background-image:url('paperBackground.jpg'); padding: 20px; } .itemIcon { float:left; } .itemIcon p { font-size: 8pt; margin: 5px 0 0 0; } .itemBody h1 { font-size: 18pt; color: brown; margin: 0 0 10px 0; } .clear { clear: both; } </style> <body> <div id="content"> <div class="item"> <div class="itemIcon" style="width: 70px; padding-left: -80px"> <img src="icon.png" alt=""/> <p>This is the caption that is under the image.</p> </div> <div class="itemBody" style="margin-left: 80px"> <h1>This is the first item</h1> <p>Aliquid aliquam fabulas duo an, eu delenit intellegebat has, in sit commodo aliquip. Inermis neglegentur vis an, ea mei habeo animal verterem. Cum vivendo intellegam disputando id, usu id dicta harum convenire. Cibo corpora ut pri, sed legere probatus aliquyam no, vidisse suscipiantur eu mea. Modus etiam concludaturque pro an, ut latine quaeque per. Harum ignota mnesarchum pri ad, duo et diam oblique epicurei, pri ne vivendo omnesque epicurei.</p> <p>Aliquid aliquam fabulas duo an, eu delenit intellegebat has, in sit commodo aliquip. Inermis neglegentur vis an, ea mei habeo animal verterem. Cum vivendo intellegam disputando id, usu id dicta harum convenire. Cibo corpora ut pri, sed legere probatus aliquyam no, vidisse suscipiantur eu mea. Modus etiam concludaturque pro an, ut latine quaeque per. Harum ignota mnesarchum pri ad, duo et diam oblique epicurei, pri ne vivendo omnesque epicurei.</p> </div> </div> <div class="item"> <div class="itemIcon" style="width: 160px; padding-left: -170px"> <img src="bigIcon.png" alt=""/> <p>This is the caption that is under the image and it is a very long text so it is going to wrap a couple times here in the left column under the image.</p> </div> <div class="itemBody" style="margin-left: 170px"> <h1>This is the second item</h1> <p>Aliquid aliquam fabulas duo an, eu delenit intellegebat has, in sit commodo aliquip. Inermis neglegentur vis an, ea mei habeo animal verterem. Cum vivendo intellegam disputando id, usu id dicta harum convenire. Cibo corpora ut pri, sed legere probatus aliquyam no, vidisse suscipiantur eu mea. Modus etiam concludaturque pro an, ut latine quaeque per. Harum ignota mnesarchum pri ad, duo et diam oblique epicurei, pri ne vivendo omnesque epicurei.</p> <p>Aliquid aliquam fabulas duo an, eu delenit intellegebat has, in sit commodo aliquip. Inermis neglegentur vis an, ea mei habeo animal verterem. Cum vivendo intellegam disputando id, usu id dicta harum convenire. Cibo corpora ut pri, sed legere probatus aliquyam no, vidisse suscipiantur eu mea. Modus etiam concludaturque pro an, ut latine quaeque per. Harum ignota mnesarchum pri ad, duo et diam oblique epicurei, pri ne vivendo omnesque epicurei.</p> </div> </div> </div> </body> </html> |
How to convert a tabbed outline text to a XAML TreeView This example shows how an outline text created with tabs can be converted XAML tree view. ![]() > > > Download Code XAML:
<Window x:Class="TestMakeOutline833.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="650"> <Window.Resources> <HierarchicalDataTemplate x:Key="sectionTemplate" ItemsSource="{Binding OutlineObjects}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Line}" /> </StackPanel> </HierarchicalDataTemplate> </Window.Resources> <StackPanel Margin="10"> <StackPanel Orientation="Horizontal" Margin="0 0 0 10"> <ScrollViewer Width="300" Height="200" Margin="0 0 10 0"> <TextBox x:Name="MainTextBox" AcceptsReturn="True" AcceptsTab="True" Text="{Binding OutlineText}"/> </ScrollViewer> <TreeView ItemsSource="{Binding OutlineObjects}" Width="200" Height="200" ItemTemplate="{StaticResource sectionTemplate}"> </TreeView> </StackPanel> <StackPanel HorizontalAlignment="Left"> <Button Content="Convert Text to Outline" Click="Button_Click_Convert"/> </StackPanel> </StackPanel> </Window> Code Behind:
using System;
using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Documents; using System.ComponentModel; using System.Collections.ObjectModel; namespace TestMakeOutline833 { public partial class Window1 : Window, INotifyPropertyChanged { #region ViewModelProperty: OutlineText private string _outlineText; public string OutlineText { get { return _outlineText; } set { _outlineText = value; OnPropertyChanged("OutlineText"); } } #endregion // #region ViewModelProperty: OutlineObjects private ObservableCollection<OutlineObject> _outlineObjects = new ObservableCollection<OutlineObject>(); public ObservableCollection<OutlineObject> OutlineObjects { get { return _outlineObjects; } set { _outlineObjects = value; OnPropertyChanged("OutlineObjects"); } } #endregion // public Window1() { InitializeComponent(); DataContext = this; OutlineText = StringHelpers.GetDefaultTextBlock(); MainTextBox.Focus(); BuildOutline(); } #region INotifiedProperty Block public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } #endregion // void Button_Click_Convert(object sender, RoutedEventArgs e) { BuildOutline(); } void BuildOutline() { OutlineObjects.Clear(); OutlineManager om = new OutlineManager(OutlineText); foreach (var outlineObject in om.OutlineObjects) { OutlineObjects.Add(outlineObject); } } } public class OutlineManager { private string outlineBlock; private List<string> outlineBlockLines; public List<OutlineObject> OutlineObjects { get; set; } public OutlineManager(string outlineBlock) { this.outlineBlock = outlineBlock; this.outlineBlockLines = StringHelpers.ConvertBlockToLines(outlineBlock); OutlineObjects = new List<OutlineObject>(); ProcessOutline(); } void ProcessOutline() { //convert file contents to object collection Stack<OutlineObject> parents = new Stack<OutlineObject>(); int lastLevel = 0; foreach (var line in outlineBlockLines) { OutlineObject oo = new OutlineObject(line); if (oo.Level == 0) { //root element OutlineObjects.Add(oo); parents.Push(oo); lastLevel = 0; } else if (oo.Level - lastLevel > 1) { //skipped generation(s) throw new Exception("outline structure invalid"); } else if (oo.Level - lastLevel == 1) { //child element OutlineObject topObject = parents.Peek(); topObject.OutlineObjects.Add(oo); parents.Push(oo); lastLevel++; } else if (oo.Level == lastLevel) { //sibling element parents.Pop(); OutlineObject topObject = parents.Peek(); topObject.OutlineObjects.Add(oo); parents.Push(oo); } else if (oo.Level < lastLevel) { int levelDifference = lastLevel - oo.Level; for (int i = 0; i < levelDifference + 1; i++) { parents.Pop(); } OutlineObject topObject = parents.Peek(); topObject.OutlineObjects.Add(oo); parents.Push(oo); lastLevel = oo.Level; } } } public static List<OutlineObject> GetOutline(string block) { OutlineManager om = new OutlineManager(block); return om.OutlineObjects; } } public class OutlineObject { public List<OutlineObject> OutlineObjects { get; set; } public string Line { get; set; } public int Level { get; set; } public OutlineObject(string rawLine) { OutlineObjects = new List<OutlineObject>(); Level = rawLine.CountPrecedingDashes(); Line = rawLine.Trim(new char[] { '-', ' ', 't' }); } } public static class StringHelpers { public static string GetDefaultTextBlock() { return "countries" + Environment.NewLine + "tfrance" + Environment.NewLine + "ttparis" + Environment.NewLine + "ttbordeaux" + Environment.NewLine + "tgermany" + Environment.NewLine + "tthamburg" + Environment.NewLine + "ttberlin" + Environment.NewLine + "tthannover" + Environment.NewLine + "ttmunich" + Environment.NewLine + "titaly" + Environment.NewLine + "subjects" + Environment.NewLine + "tmath" + Environment.NewLine + "ttalgebra" + Environment.NewLine + "ttcalculus" + Environment.NewLine + "tscience" + Environment.NewLine + "ttchemistry" + Environment.NewLine + "ttbiology" + Environment.NewLine + "other" + Environment.NewLine + "tthis" + Environment.NewLine + "tthat"; } public static int CountPrecedingDashes(this string line) { int tabs = 0; StringBuilder sb = new StringBuilder(); foreach (var c in line) { if (c == 't') tabs++; else break; } return tabs; } public static List<string> ConvertBlockToLines(this string block) { string fixedBlock = block.Replace(Environment.NewLine, "§"); List<string> lines = fixedBlock.Split('§').ToList<string>(); lines.ForEach(s => s = s.Trim()); lines.TrimBlankLines(); return lines; } public static void TrimBlankLines(this List<string> list) { while (0 != list.Count && string.IsNullOrEmpty(list[0])) { list.RemoveAt(0); } while (0 != list.Count && string.IsNullOrEmpty(list[list.Count - 1])) { list.RemoveAt(list.Count - 1); } } } } |
Extension method to remove preceding and succeeding blank lines on a List<string> This extension method TrimBlankLines() does to a List<string> what Trim() does to string. ![]()
using System;
using System.Collections.Generic; namespace TestLines8833 { class Program { static void Main(string[] args) { List<string> lines = new List<string>(); lines.Add(""); lines.Add("one"); lines.Add("two"); lines.Add(""); lines.Add(""); lines.Add("five"); lines.Add(""); lines.Add(""); lines.TrimBlankLines(); for (int i = 0; i < lines.Count; i++) { Console.WriteLine("{0}: {1}", i + 1, lines[i]); } Console.ReadLine(); } } public static class Helpers { public static void TrimBlankLines(this List<string> list) { while (list.Count != 0 && string.IsNullOrEmpty(list[0])) { list.RemoveAt(0); } while (list.Count != 0 && string.IsNullOrEmpty(list[list.Count - 1])) { list.RemoveAt(list.Count - 1); } } } } |
How to Create a TreeView with HierarchicalDataTemplate based on a collection of objects with collections This example gives you the basics to display an object collection that has objects with collections of those objects recursively down to any level. ![]() XAML:
<Window x:Class="TestTr32322.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TestTr32322" Title="Window1" Height="300" Width="350"> <Window.Resources> <HierarchicalDataTemplate x:Key="sectionTemplate" ItemsSource="{Binding ChildSections}" DataType="{x:Type local:Section}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Title}" /> <TextBlock Text=" - " /> <TextBlock Text="{Binding Description}" FontStyle="Italic" Foreground="#777" /> </StackPanel> </HierarchicalDataTemplate> </Window.Resources> <StackPanel> <TreeView ItemsSource="{Binding Sections}" SelectedItemChanged="TreeView_SelectedItemChanged" ItemTemplate="{StaticResource sectionTemplate}"> </TreeView> <TextBlock Text="{Binding Message}" Margin="0 10 0 0"/> </StackPanel> </Window> Code Example:
using System.Windows;
using System.ComponentModel; using System.Collections.ObjectModel; using System.Windows.Controls; using System; namespace TestTr32322 { public partial class Window1 : Window, INotifyPropertyChanged { #region ViewModelProperty: Sections private ObservableCollection<Section> _sections = new ObservableCollection<Section>(); public ObservableCollection<Section> Sections { get { return _sections; } set { _sections = value; OnPropertyChanged("Sections"); } } #endregion test #region ViewModelProperty: Message private string _message; public string Message { get { return _message; } set { _message = value; OnPropertyChanged("Message"); } } #endregion test public Window1() { InitializeComponent(); DataContext = this; Sections = Section.GetSections(); } #region INotifiedProperty Block public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } #endregion test private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { TreeView tw = ((TreeView)sender); Section selectedSection = tw.SelectedItem as Section; Message = String.Format("You choose {0} (Id={1})", selectedSection.Title, selectedSection.Id); } } public class Section : INotifyPropertyChanged { public int Id { get; set; } public string Title { get; set; } public string Description { get; set; } #region ViewModelProperty: ChildSections private ObservableCollection<Section> _childsections = new ObservableCollection<Section>(); public ObservableCollection<Section> ChildSections { get { return _childsections; } set { _childsections = value; OnPropertyChanged("ChildSections"); } } #endregion test public static ObservableCollection<Section> GetSections() { ObservableCollection<Section> sections = new ObservableCollection<Section>(); { sections.Add(new Section {Id = 1, Title = "First Section", Description = "first description" }); sections.Add(new Section { Id = 2, Title = "Second Section", Description = "second description" }); sections.Add(new Section { Id = 3, Title = "Third Section", Description = "third description" }); ObservableCollection<Section> grandchildren = new ObservableCollection<Section>(); grandchildren.Add(new Section { Id = 5, Title = "Grandchild Section 1", Description = "grandchild description" }); grandchildren.Add(new Section { Id = 6, Title = "Grandchild Section 2", Description = "grandchild description" }); Section section = new Section(); section.Id = 4; section.Title = "Fourth Section"; section.Description = "fourth description"; section.ChildSections.Add(new Section { Id = 7, Title = "Child Section", Description = "this is a child description", ChildSections = grandchildren }); sections.Add(section); } return sections; } #region INotifiedProperty Block public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } #endregion test } } |
How to check for first and last items in a foreach loop This was one of the the many interesing ideas for avoiding index counter messiness in foreach loops. This reads nicely for short lists, e.g. dropdown/radiobutton collections, etc. but it is not resourceful for large lists (because .last() iterates through the collection) and it assumes all values are unique. ![]()
using System; using System.Collections.Generic; using System.Linq; namespace TestForEach23433 { class Program { static void Main(string[] args) { List<string> names = new List<string> { "Smith", "Jones", "Rogers", "Anderson" }; var first = names.First(); var last = names.Last(); foreach (var name in names) { Console.Write(name); if (name == first) Console.WriteLine(" (first)"); else if (name == last) Console.WriteLine(" (last)"); else Console.WriteLine(); } Console.ReadLine(); } } } |
How to format text in a WPF application (bold, italic, colored, hyperlinks, etc.) I needed an easy way to display text with simple formatting (bold, italic, colors, hyperlinks) in a WPF application. This example gives you the basis to create custom markup that is converted into a FlowDocument. It is easy to create other codes which represent other formatting that you need for your application, copy and add a block in the switch statement. ![]() XAML:
<Window x:Class="TestFlow23993.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <StackPanel Margin="10"> <ContentControl x:Name="MainArea"/> </StackPanel> </Window>
using System.Collections.Generic;
using System.Linq; using System.Windows; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Controls; using System.Windows.Input; using System; using System.Diagnostics; namespace TestFlow23993 { public partial class Window1 : Window { public Window1() { InitializeComponent(); StackPanel sp = new StackPanel(); sp.AddMarkedUpText("You want to {i:always} use this class so it is both {b:easy} and {b:straight-forward} to format documents. Here are some examples of {b:camel-case} strings: {ex:firstName}, {ex:lastName}, {ex:title}, and {ex:allowUserToFilterRows}."); sp.AddMarkedUpText("This is the second paragraph which allows you to link to {link:google>>>http://www.google.com}."); sp.AddMarkedUpText("Here's another paragraph with no formatting."); MainArea.Content = sp; } } public class FlowDocumentParser { private string markedUpText; private List<string> parts; private FlowDocument doc; public int FontSize { get; set; } public string FontFamily { get; set; } public TextAlignment TextAlignment { get; set; } public FlowDocumentParser(string markedUpText) { this.markedUpText = markedUpText; parts = markedUpText.Split(new char[] { '{', '}' }).ToList(); SetDefaults(); } void SetDefaults() { FontSize = 12; FontFamily = "Arial"; TextAlignment = TextAlignment.Left; } public void BuildFlowDocument() { doc = new FlowDocument(); doc.PagePadding = new Thickness(0); Paragraph paragraph = new Paragraph(); paragraph.TextAlignment = TextAlignment; doc.Blocks.Add(paragraph); foreach (var part in parts) { //ITALIC, e.g. "{i:this is italic}" if (part.StartsWith("i:")) { string text = part.ChopLeft("i:"); Run run = AddPart(paragraph, text); run.FontStyle = FontStyles.Italic; } //BOLD, e.g. "{b:this is bold}" else if (part.StartsWith("b:")) { string text = part.ChopLeft("b:"); Run run = AddPart(paragraph, text); run.FontWeight = FontWeights.Bold; } //EXAMPLE TEXT, e.g. "{ex:this is an example}" else if (part.StartsWith("ex:")) { string text = part.ChopLeft("ex:"); Run run = AddPart(paragraph, text); run.FontWeight = FontWeights.Bold; run.Foreground = new SolidColorBrush(Colors.Brown); } //HYPERLINK, e.g. "{link:google>>>http://www.google.com}" else if (part.StartsWith("link:")) { string text = part.ChopLeft("link:"); List<string> pieces = text.SplitWithStringSeparator(">>>"); string linkText = pieces[0]; string linkUrl = pieces[1]; Run run = new Run(linkText); run.FontSize = FontSize; run.FontFamily = new FontFamily(FontFamily); run.Foreground = new SolidColorBrush(Colors.Blue); run.Cursor = Cursors.Hand; Hyperlink hl = new Hyperlink(run); hl.NavigateUri = new Uri(linkUrl); hl.Foreground = new SolidColorBrush(Colors.Blue); hl.RequestNavigate += new System.Windows.Navigation.RequestNavigateEventHandler(hl_RequestNavigate); paragraph.Inlines.Add(hl); } else { Run run = AddPart(paragraph, part); } } } void hl_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) { Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)); e.Handled = true; } Run AddPart(Paragraph paragraph, string text) { Run run = new Run(text); paragraph.Inlines.Add(run); run.FontSize = FontSize; run.FontFamily = new FontFamily(FontFamily); return run; } public FlowDocument GetBuiltFlowDocument() { return doc; } public static FlowDocument GetFlowDocument(string markedUpText) { FlowDocumentParser fdp = new FlowDocumentParser(markedUpText); fdp.BuildFlowDocument(); return fdp.GetBuiltFlowDocument(); } } public static class StringHelpers { public static string ChopLeft(this string line, string removeThis) { int removeThisLength = removeThis.Length; if (line.Length >= removeThisLength) { if (line.StartsWith(removeThis)) return line.Substring(removeThisLength, line.Length - removeThisLength); else return line; } else return line; } public static List<string> SplitWithStringSeparator(this string line, string separator) { return line.Split(new string[] { separator }, StringSplitOptions.None).ToList(); } } public static class XamlHelpers { public static void AddMarkedUpText(this StackPanel sp, string markedUpText) { FlowDocumentScrollViewer fdsv = new FlowDocumentScrollViewer(); FlowDocument fd = FlowDocumentParser.GetFlowDocument(markedUpText); fdsv.Document = fd; fdsv.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden; fdsv.Margin = new Thickness { Bottom = 10 }; sp.Children.Add(fdsv); } } } |
Two ways to set focus in a programmatically created textbox This example shows you two ways to set focus for a programmatically created TextBox. If you need to set focus WHILE you are adding the TextBoxes for some reason, use the hack (thanks to Adam Nelson), otherwise, if you can, wait till AFTER you have set the ContentControl and then set focus via the parent of the TextBoxes. ![]() XAML:
<Window x:Class="TestFocksdfj.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <StackPanel HorizontalAlignment="Left" Margin="10"> <ContentControl x:Name="FormArea"/> </StackPanel> </Window> Code Behind:
using System.Windows;
using System.Windows.Controls; using System.Threading; using System; using System.Windows.Input; namespace TestFocksdfj { public partial class Window1 : Window { public Window1() { InitializeComponent(); StackPanel sp = new StackPanel(); for (int i = 0; i < 3; i++) { TextBox tb = new TextBox(); tb.Width = 200; tb.Margin = new Thickness { Bottom = 3 }; if (i == 2) { //FocusHelper.Focus(tb); //SOLUTION 1 with hack } sp.Children.Add(tb); } FormArea.Content = sp; //SOLUTION 2 without hack: sp.Children[1].Focus(); } } //hack: static class FocusHelper { private delegate void MethodInvoker(); public static void Focus(UIElement element) { ThreadPool.QueueUserWorkItem(delegate(Object foo) { UIElement elem = (UIElement)foo; elem.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (MethodInvoker)delegate() { elem.Focus(); Keyboard.Focus(elem); }); }, element); } } } |









