public static class DriveInfoExtender { public static bool IsDriveFree(string drive) { if (string.IsNullOrEmpty(drive) || !char.IsLetter(drive[0])) return false; if (drive.Length >= 2) drive = drive.Substring(0,1).ToUpper(); bool isFree = true; DriveInfo[] nonFreeDrives = System.IO.DriveInfo.GetDrives(); foreach (DriveInfo di in nonFreeDrives) { if (di.Name.StartsWith(drive)) { isFree = false; break; } } return isFree; } }
December 15, 2010
IsDrivefree
A simple helper to check if a specified drive letter is free for use:
November 29, 2010
AssemblyVersion and AssemblyFileVersion
See here
and here
and here
- AssemblyVersion is .NET version info whilst 'AssemblyFileVersion' is Windows version number, ie., what you see when you do view the file properties of an assembly in windows explorer. AssemblyVersion defines the version other assemblies are compiled against in their manifest.
- If 'AssemblyFileVersion' attribute is not present in 'AssemblyInfo.cs' then AssemblyFileVesrion takes the same value as AssemblyVersion.
Labels:
AssemblyFileVersion,
AssemblyVersion
November 4, 2010
Proxy, Decorator, Adapter, Bridge and Facade Patterns
Found the following explanantion here. It is a useful description of the differences between these patterns as they are very similar.
Proxy, Decorator, Adapter, and Bridge are all variations on "wrapping" a class. But their uses are different:
Proxy, Decorator, Adapter, and Bridge are all variations on "wrapping" a class. But their uses are different:
- Proxy could be used when you want to lazy-instantiate an object, or hide the fact that you're calling a remote service, or control access to the object.
- Decorator is also called "Smart Proxy." This is used when you want to add functionality to an object, but not by extending that object's type. This allows you to do so at runtime.
- Adapter is used when you have an abstract interface, and you want to map that interface to another object which has similar functional role, but a different interface.
- Bridge is very similar to Adapter, but we call it Bridge when you define both the abstract interface and the underlying implementation. I.e. you're not adapting to some legacy or third-party code, you're the designer of all the code but you need to be able to swap out different implementations.
- Facade is a higher-level (read: simpler) interface to a subsystem of one or more classes. Think of Facade as a sort of container for other objects, as opposed to simply a wrapper.
November 2, 2010
Deleting a Read-Only File
See also the FileAttributesExtender class
and the PathCombine class
and the PathCombine class
string fullPath = PathCombine(pathRoot, relativePath); if (File.Exists(fullPath)) { FileAttributes fas = File.GetAttributes(fullPath); if (fas.Contains(FileAttributes.ReadOnly)) File.SetAttributes(fullPath, FileAttributes.Normal); File.Delete(fullPath); }
October 22, 2010
String Conversion C++ C#
C++/CLi to C#
C# to C++
std::string str = ...; System::String^ mgdstr = gcnew System::String(str.c_str();and the other way
C# to C++
System::String^ value = ...; CString cstr(value); const std::string converted(cstr);
October 13, 2010
Static Property Reflection Sample
This sample enumerates over the "TargetClass" looking for all static properties that return the specified "ReturnType"
public static IEnumerableEnumerateReturnTypeProperties() { Type type = typeof(TargetClass); PropertyInfo[] props = type.GetProperties(); foreach (PropertyInfo prop in props) { // null as 1st GetValue parameter implies // only static properties enumerated ReturnType xxx = prop.GetValue(null, null) as ReturnType; if (xxx == null) continue; yield return xxx; } }
Path.Combine
See here for a description of the behaviour of this method.
Following method resolves some weaknesses in the static method "Path.Combine" found in the System.IO namespace.
Following method resolves some weaknesses in the static method "Path.Combine" found in the System.IO namespace.
public static string PathCombine(string rootPath, string relativePath) { Debug.Assert(rootPath != null); Debug.Assert(relativePath != null); string res = string.Empty; if (rootPath.EndsWith(":")) { rootPath += @"\"; } // remove initial single '\' or '/' from relative path if (relativePath.StartsWith(@"\") || relativePath.StartsWith(@"/")) { if (! (relativePath.StartsWith(@"\\") || relativePath.StartsWith(@"//"))) { relativePath = relativePath.Substring(1); } } res = Path.Combine(rootPath, relativePath); res = res.Replace('/', '\\'); // replace '/' with '\' return res; }
October 6, 2010
More Complex Progress Dialog
This sample does a file search asynchronously. At the end of the search the progress dialog pauses and closes itself. Internally a timer is used to initiate this automatic close of the progress dialog. AsynchFileFinder is the BackgroundWorker derived object.
Here is th Xaml for the dialog:
<Window x:Class="FindingFilesDlg" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Finding modified files" Height="167" Width="514" Closing="Window_Closing" Loaded="Window_Loaded"> <Grid> <Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,12" Name="butCancel" VerticalAlignment="Bottom" Width="91" Click="butCancelDone_Click">_Cancel</Button> <TextBlock Height="21" Margin="12,15,0,0" Name="tbActivity" VerticalAlignment="Top" Text="Searching for modified files:" HorizontalAlignment="Left" Width="Auto" /> <ProgressBar Margin="12,61,0,52" Name="progressBar" HorizontalAlignment="Left" Width="427" /> <TextBlock Margin="0,61,16,52" Name="tbPercentage" Text="0%" HorizontalAlignment="Right" Width="31" TextAlignment="Right" /> </Grid> </Window>Here is the code for the dialog:
public partial class FindingFilesDlg : Window { AsyncFileFinder m_AsyncFileFinder = null; DispatcherTimer m_Timer = new DispatcherTimer(); IEnumerable<FileSystemInfo> m_FilesFound = new FileSystemInfo[0]; int countDown = 1; const int SECOND = 10000000; bool m_Completed = false; public FindingFilesDlg(string rootDir, FileSearchRules fsr) { InitializeComponent(); tbActivity.Text = "Preparing to search \'" + rootDir + "\' for modified files:"; InitialiseTimer(); InitialiseAsyncFileFinder(rootDir, fsr); } private void InitialiseAsyncFileFinder( string rootDir, FileSearchRules fsr) { // The BackgroundWorker derived object m_AsyncFileFinder = new AsyncFileFinder(rootDir, fsr); m_AsyncFileFinder.ProgressChanged += new ProgressChangedEventHandler( AsynchFileFinder_ProgressChanged); m_AsyncFileFinder.RunWorkerCompleted += new RunWorkerCompletedEventHandler( AsynchFileFinder_RunWorkerCompleted); } private void InitialiseTimer() { // Disable timer m_Timer.IsEnabled = false; // Set timer event interval m_Timer.Interval = new TimeSpan((long)(1 * SECOND)); // Timer events m_Timer.Tick += new EventHandler(timer_Tick); } public IEnumerable<FileSystemInfo> FilesFound { get { return m_FilesFound; } } void AsynchFileFinder_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { if (!e.Cancelled) { m_Completed = true; m_FilesFound = m_AsyncFileFinder.Files; tbActivity.Text = "Finished searching \'" + m_AsyncFileFinder.SearchDirectory + "\', " + m_FilesFound.Count().ToString() + " files found"; progressBar.Value = progressBar.Maximum; tbPercentage.Text = "100%"; UpdateDoneButton(); // wait several seconds before closing the dialog m_Timer.Start(); } } void UpdateDoneButton() { string str = "_Done (" + countDown.ToString() + ")"; butCancel.Content = str; } bool textUpdated = false; void AsynchFileFinder_ProgressChanged(object sender, ProgressChangedEventArgs e) { Debug.Assert((e.ProgressPercentage >= 0) && (e.ProgressPercentage <= 100)); progressBar.Value = e.ProgressPercentage; tbPercentage.Text = e.ProgressPercentage.ToString() + "%"; if ((e.ProgressPercentage > 1) && !textUpdated) { textUpdated = true; tbActivity.Text = "Searching \'" + m_AsyncFileFinder.SearchDirectory + "\' for modified files (" + m_AsyncFileFinder.NumFilesToSearch.ToString() + " files to search) :"; } } private void Window_Closing(object sender, CancelEventArgs e) { CancelAsyncFileFinder(); if (m_Timer.IsEnabled) StopTimer(); m_AsyncFileFinder.Dispose(); } private void Window_Loaded(object sender, RoutedEventArgs e) { m_AsyncFileFinder.RunWorkerAsync(); tbActivity.Text = "Searching \'" + m_AsyncFileFinder.SearchDirectory + "\' for modified files:"; } // wait several seconds before closing the dialog void timer_Tick(object sender, EventArgs e) { --countDown; UpdateDoneButton(); if (countDown == 0) { StopTimer(); DialogResult = m_Completed; } } private void StopTimer() { m_Timer.Stop(); } private void butCancelDone_Click(object sender, RoutedEventArgs e) { if (!m_Completed) { CancelAsyncFileFinder(); if (m_Timer.IsEnabled) StopTimer(); } DialogResult = m_Completed; } private void CancelAsyncFileFinder() { if (m_AsyncFileFinder.IsBusy) m_AsyncFileFinder.CancelAsync(); } }Here is the code for the background worker object:
internal class AsyncFileFinder : BackgroundWorker { private FileSearchRules FileSearchRules { get; set; } string m_RootDir = string.Empty; List<System.IO.FileSystemInfo> files = new List<System.IO.FileSystemInfo>(); int m_NumberFilesToSearch = 0; // Pass required info in through constructor, // cant change it whilst a search is underway public AsyncFileFinder(string rootDir, FileSearchRules fsr) : base() { this.WorkerReportsProgress = true; this.WorkerSupportsCancellation = true; m_RootDir = rootDir; FileSearchRules = new FileSearchRules(fsr); } public string SearchDirectory { get { return m_RootDir; } } public IEnumerable<FileSystemInfo> Files { get { if (IsBusy) // No access while thread active return new List<FileSystemInfo>(); else return files.AsReadOnly(); } } // Total number of files that will be checked public int NumFilesToSearch { get { return m_NumberFilesToSearch; } } protected override void OnDoWork(DoWorkEventArgs e) { bool cancelled = false; double progress = 0; double prevProgress = 0; files = new List<FileSystemInfo>(); DirectoryInfo targ = new DirectoryInfo(m_RootDir); // Count the number of files to process first foreach (System.IO.FileSystemInfo fsi in targ.IterateFiles(true)) { if (CancellationPending) { cancelled = true; break; } Interlocked.Increment(ref m_NumberFilesToSearch); } int count = 0; if (!cancelled) { foreach (FileSystemInfo fsi in targ.IterateFiles(true)) { if (CancellationPending) { cancelled = true; break; } ++count; // progress as a percentage progress = (100.0 * (double)count / (double)m_NumberFilesToSearch) + 0.5; // Report every 1% of progress if ((progress - prevProgress) > 1.0) { ReportProgress((int)(progress)); prevProgress = progress; } if (FileSearchRules.PassesRules(fsi)) { files.Add(fsi); } } } e.Cancel = cancelled; } }
General Purpose Progess Dialog
This is a general purpose progress dialog. It takes a background worker object as a parameter.
Here is the Xaml for the dialog:
<Window x:Class="AsyncMessageDlg" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="AsyncMessageDlg" Height="314" Width="750" WindowStartupLocation="CenterOwner" Closing="Window_Closing" Loaded="Window_Loaded"> <Grid> <Ellipse Fill="Azure" Height="56" Margin="0,27,120,0" Name="ellipse2" Stroke="Beige" VerticalAlignment="Top" HorizontalAlignment="Right" Width="82" /> <Ellipse Fill="Azure" Height="56" Margin="120,0,0,20" Name="ellipse1" Stroke="Beige" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="82" /> <TextBox Margin="12,35,12,63" Name="textBox" IsReadOnly="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" /> <Button Height="23" Margin="560,0,0,6" VerticalAlignment="Bottom" Name="butOK" HorizontalAlignment="Left" Width="75" IsDefault="True" Click="butOK_Click">_Ok</Button> <Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,6" Name="butCancel" VerticalAlignment="Bottom" Width="75" IsCancel="True" Click="butCancel_Click">_Cancel</Button> <Label Height="28" Margin="12,7,12,0" Name="label" VerticalAlignment="Top">Label</Label> <ProgressBar Height="16" Margin="120,0,181,41" Name="progressBar" VerticalAlignment="Bottom" Visibility="Hidden" /> <TextBlock Height="16" HorizontalAlignment="Right" Margin="0,0,144,41" Name="tbProgressPercent" Text="0%" TextAlignment="Right" VerticalAlignment="Bottom" Width="31" Visibility="Hidden" /> </Grid> </Window>The dialog takes a string for the dialog title and a string for the label above the output text window. When the background worker task sends a progress update it tries to convert the UserState object passed in the event to a string which is added to the output window. Here is the code for the dialog:
public partial class AsyncMessageDlg : Window { BackgroundWorker m_WorkerThread = null; bool m_Completed = false; public AsyncMessageDlg( string textBoxTitle, string dlgTitle, BackgroundWorker bw) { Debug.Assert(bw != null); InitializeComponent(); this.Title = dlgTitle; this.label.Content = textBoxTitle; m_Completed = false; InitialiseBackgrounWorker(bw); } private void InitialiseBackgrounWorker(BackgroundWorker bw) { Debug.Assert(bw != null); Debug.Assert(bw.WorkerSupportsCancellation); this.m_WorkerThread = bw; //if (m_WorkerThread.WorkerReportsProgress) butCancel.IsEnabled = m_WorkerThread.WorkerSupportsCancellation; butOK.IsEnabled = false; tbProgressPercent.Visibility = Visibility.Visible; progressBar.Visibility = Visibility.Visible; m_WorkerThread.ProgressChanged += new ProgressChangedEventHandler( m_WorkerThread_ProgressChanged); m_WorkerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler( m_WorkerThread_RunWorkerCompleted); } void m_WorkerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) return; m_Completed = true; string result = e.Result as string; if (result != null) { label.Content = result as string; } progressBar.Value = progressBar.Maximum; tbProgressPercent.Text = "100%"; butOK.IsEnabled = true; butCancel.IsEnabled = false; } void m_WorkerThread_ProgressChanged(object sender, ProgressChangedEventArgs e) { Debug.Assert((e.ProgressPercentage >= 0) && (e.ProgressPercentage <= 100)); progressBar.Value = e.ProgressPercentage; tbProgressPercent.Text = e.ProgressPercentage.ToString() + "%"; if (e.UserState != null) { if (e.UserState is string) { textBox.Text += e.UserState as string; } else { textBox.Text += e.UserState.ToString(); } } } private void Window_Loaded(object sender, RoutedEventArgs e) { m_WorkerThread.RunWorkerAsync(); } private void Window_Closing(object sender, CancelEventArgs e) { CancelWorkerThread(); m_WorkerThread.Dispose(); } private void butOK_Click(object sender, RoutedEventArgs e) { DialogResult = m_Completed; this.Close(); } private void butCancel_Click(object sender, RoutedEventArgs e) { if (!m_Completed) { CancelWorkerThread(); } DialogResult = m_Completed; } private void CancelWorkerThread() { if (m_WorkerThread.IsBusy && m_WorkerThread.WorkerSupportsCancellation) m_WorkerThread.CancelAsync(); } }Here is the code for a sample background worker
// Background worker to check out some files internal class AsynchAddCheckOutFiles : BackgroundWorker { List<FileSystemInfo> m_fileSystemInfoList; // Pass required info in through constructor, cant change it // whilst a search is underway public AsynchAddCheckOutFiles(ref List<FileSystemInfo> fileSystemInfoList) : base() { this.m_fileSystemInfoList = fileSystemInfoList; // Set clients refernce to null, we own the list. fileSystemInfoList = null; this.WorkerReportsProgress = true; this.WorkerSupportsCancellation = true; } protected override void OnDoWork(DoWorkEventArgs e) { bool cancelled = false; double progress = 0; double prevProgress = 0; int m_NumberFiles = m_fileSystemInfoList.Count; int count = 0; if (!cancelled) { foreach (FileSystemInfo fsi in m_fileSystemInfoList) { if (CancellationPending) { cancelled = true; break; } Perforce.P4CommandTransaction res = Perforce.Instance.AddCheckOutFile(fsi); string state = res.ToString(); ++count; // progress as a percentage progress = (100.0 * (double)count / (double)m_NumberFiles) + 0.5; // Report every 1% of progress if ((progress - prevProgress) > 1.0) { ReportProgress((int)(progress), state); prevProgress = progress; } } } e.Cancel = cancelled; } }
September 28, 2010
September 22, 2010
Timespan Formatting
timeSpan.ToString("hh:mm:ss") equivalent. (Only available in .Net 4!)
TimeSpan timeSpan = new TimeSpan(DateTime.UtcNow.Ticks - scriptTime.Ticks); string timeStr = timeSpan.Hours.ToString().PadLeft(2, '0') + ":" + timeSpan.Minutes.ToString().PadLeft(2, '0') + ":" + timeSpan.Seconds.ToString().PadLeft(2, '0');
July 29, 2010
StringCollection Class Extender
A helper class for the StringCollection class.
public static class StringCollectionExtender { // Convert a string collection to a multiline string where // each entry in the collection becomes a line in // multi-line string public static string ToMultilineString( this StringCollection sc) { StringBuilder res = new StringBuilder(); foreach (string str in sc) { res.AppendLine(str); } return res.ToString(); } public static string[] ToStringArray( this StringCollection sc) { string[] res = new string[sc.Count]; sc.CopyTo(res, 0); return res; } // Convert a multiline string to a string collection with each line // of the string becoming a new entry in the collection public static StringCollection MultilineStringToStringCollection( string str) { string[] lines = str.Split('\r'); StringCollection res = new StringCollection(); foreach (string line in lines) { res.Add(line.Trim('\n')); } return res; } }
July 28, 2010
Assembly Version Incrementor
Find and increment the assembly version info in an Assembly info file
public class AssemblyVersionIncrementor { public void IncrementAssemblyVersionString(FileSystemInfo fileInfo) { string[] lines = File.ReadAllLines(fileInfo.FullName); lines = IncrementAssemblyVersionString(lines); File.WriteAllLines(fileInfo.FullName, lines); } internal string[] IncrementAssemblyVersionString(string[] lines) { string[] res = new string[lines.Length]; int ix = 0; foreach (string line in lines) { res[ix++] = IncrementAssemblyVersionString(line); } return res; } // Could be modified to find other types of Version Info by // making the "AssemblyVersion" a parameter internal string IncrementAssemblyVersionString(string line) { string res = line; if (line.Contains("AssemblyVersion")) { string newLine = string.Empty; string str = line; // Check for comments int commentStart = line.IndexOf("//"); // TODO /* ... */ style comments if (commentStart >= 0) { str = line.Substring(0, commentStart); } if (str.Contains("AssemblyVersion")) { int start = str.IndexOf('"') + 1; int end = str.IndexOf('"', start); string assemblyVerStr = str.Substring(start, end - start); Version av = new Version(assemblyVerStr); Version newVer = av.IncrementRevision(); newLine = line.Substring(0, start) + newVer.ToString() + line.Substring(end, line.Length - end); } res = newLine.Length > 0 ? newLine : line; } return res; } }uses the following Version extension class:
internal static class VersionExtender { public static Version Increment(this Version version) { return Increment(version, 0x1L); } public static Version IncrementMajor(this Version version) { return Increment(version, 0x1000000000000L); } public static Version IncrementMinor(this Version version) { return Increment(version, 0x100000000L); } public static Version IncrementBuild(this Version version) { return Increment(version, 0x10000L); } public static Version IncrementRevision(this Version version) { return Increment(version, 0x1L); } // Good demo of using >> and << operators as well private static Version Increment(this Version version, ulong inc) { ulong versnNum = (((ulong)version.Major & 0xFFFF) << 48) + (((ulong)version.Minor & 0xFFFF) << 32) + (((ulong)version.Build & 0xFFFF) << 16) + ((ulong)version.Revision & 0xFFFF); versnNum += inc; UInt16 major = (UInt16)(versnNum >> 48); UInt16 minor = (UInt16)((versnNum >> 32) & 0xFFFF); UInt16 build = (UInt16)((versnNum >> 16) & 0xFFFF); UInt16 revision = (UInt16)(versnNum & 0xFFFF); return new Version(major, minor, build, revision); } }
Labels:
AssemblyVersion,
Bit shift operators,
extension class,
Version
July 21, 2010
Quickly Add Xml To XmlDocument
This line loads an Xml document, looks for the presence of a particular line and if it is not there, adds it to the xml document. This is useful for updating a config file with a particular line of xml. Uses XPath to find the interesting element of the xml file.
public static void UpdateAnXmlNode(string xmlFileName) { XmlDocument xDoc = new XmlDocument(); try { // load the configuration file xDoc.Load(xmlFileName); // find the node of interest from the key XmlNode theNode = xDoc.SelectSingleNode( @"/configuration/xxxConfiguration/moduleGroups/add[@trustName = 'Default']/modules"); bool customXmlLinePresent = false; if (theNode != null) { customXmlLinePresent = theNode.InnerXml.Contains( "XXX.YYY.Sandbox.DebugTree.Module"); } string extraXml = string.Empty; if (!customXmlLinePresent) extraXml += @"<add moduleType=""XXX.YYY.Sandbox.DebugTree.Module, XXX.YYY.Sandbox"" />" + Environment.NewLine; if (extraXml.Length > 0) { theNode.InnerXml += extraXml; xDoc.PreserveWhitespace = true; xDoc.Save(xmlFileName); } } catch (XmlException ex) { DoSomethingWithError(ex); } }
July 16, 2010
FileSystemInfoExtender Class
Extend the FileSystemInfo class with enumerators to iterate through subdirectories, ditto with the DirectoryInfo class.
Now merged into this blog entry
Now merged into this blog entry
Labels:
DirectoryInfo,
extension class,
FileSystemInfo,
IEnumerable,
Iterators,
yield
FileAttributesExtender
Use Flags based enumerated types extender class to extend file attributes and give it Set/group theory like methods
public static class FileAttributesExtender { // Return lhs flags plus rhs flags public static FileAttributes Union(this FileAttributes lhs, FileAttributes rhs) { return lhs | rhs; } // Return flags common to lhs and rhs public static FileAttributes Intersection(this FileAttributes lhs, FileAttributes rhs) { return lhs & rhs; } // Return lhs flags minus rhs flags public static FileAttributes Difference(this FileAttributes lhs, FileAttributes rhs) { FileAttributes common = Intersection(lhs, rhs); int res = (int)lhs - (int)common; return (FileAttributes)(res); } // Return true if lhs contains ALL the flags within rhs public static bool Contains(this FileAttributes lhs, FileAttributes rhs) { FileAttributes common = Intersection(lhs, rhs); return (common == rhs); } // Return true if lhs contains any of the flags within rhs public static bool ContainsAnyOf(this FileAttributes lhs, FileAttributes rhs) { FileAttributes common = Intersection(lhs, rhs); return ((int)common > 0); } // Return true if lhs contains none of the flags within rhs public static bool ContainsNoneOf(this FileAttributes lhs, FileAttributes rhs) { FileAttributes common = Intersection(lhs, rhs); return ((int)common == 0); } // NON-extension methods here public static FileAttributes FromString(string source) { FileAttributes res = (FileAttributes)Enum.Parse(typeof(FileAttributes), source, true); return res; } }
July 9, 2010
Close or Kill a Process
This routine will try and close a process by sending a close message to it's main window. If the process has no GUI or a timeout period is exceeded then the 'Process.Kill()' method will be used to close it.
// Try and close a process. Kill it if the Close takes // too long. // exeLessExtension - Process name (without extension) // msToWaitForCloseMainWindow - Time in milliseconds to // wait for 'CloseMainWindow()' before just killing the // process, Set negative to not kill at all, set to 0 to // kill without calling CloseMainWindow public static void ForceProcessClose( string exeLessExtension, int msToWaitForCloseMainWindow) { Process[] processes = Process.GetProcessesByName(exeLessExtension); if (msToWaitForCloseMainWindow != 0) { foreach (Process p in processes) { if (!p.CloseMainWindow()) { // Process does not have a GUI, use 'Kill()' instead msToWaitForCloseMainWindow = 0; } } } if (msToWaitForCloseMainWindow >= 0) { Thread.Sleep(msToWaitForCloseMainWindow); processes = Process.GetProcessesByName(exeLessExtension); foreach (Process p in processes) { p.Kill(); } } }
July 1, 2010
Using Images in WPF
Using project resources in WPF
- Create sub-directory for resources called say "Resources"
- Add your resources (images, icons etc.) to it.
- Copy the folder structure into the VS project and add the resource files to it.
- Check the Properties of your resources in VS project file to ensure they have a Build Action of 'Resource'
<Image Source="Resources/P4.ico" />Adding an image to a window's resources is very easy:
<Window.Resources> <Image x:Key="P4Icon" Source="Resources/P4.ico" /> </Window.Resources>In code:
Image myImage = new Image();Inserting an image in a button is very easy in WPF:
myImage.Source = new BitmapImage(new Uri("Icons/MyImage.png", UriKind.Relative));
<Button HorizontalAlignment="Left" Margin="5,8,0,10" Name="p4But" Width="34" Click="p4But_Click"> <Image Source="Resources/P4.ico" Width="24" /> </Button>
Start a Process and Capture the Output in c#
Simple sample for running a process synchronously and capturing the output
public string GetEnvironmentVars() { Process process = new Process(); // UseShellExecute must be 'false' when redirecting the output process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.StartInfo.FileName = "p4"; process.StartInfo.Arguments = " set "; //process.StartInfo.WorkingDirectory = dir; process.Start(); string output = process.StandardOutput.ReadToEnd(); //string error = process.StandardError.ReadToEnd(); // Wait a reasonable ammount of time for it to finish bool res = process.WaitForExit(5000); return res ? output : "Command \"" + process.StartInfo.FileName + process.StartInfo.Arguments + "\" failed to exit:" + Environment.NewLine + output; }
Labels:
c#,
process,
RedirectStandardOutput
Editing Context Menus of Visual Studio 2008
Can add external tools to context menu.
Title: P4 Checkout
Command: C:\Program Files (x86)\Perforce\p4.exe
Arguments: edit $(ItemPath)
Initial Directory: $(ItemDir)
Select "Use Output window"
As shown here:
Title: P4 Revert
Command: C:\Program Files (x86)\Perforce\p4.exe
Arguments: revert $(ItemPath)
Initial Directory: $(ItemDir)
Select "Use Output window"
- Create your external tool using the "Tools=>External Tools" menu option. Your new external tool will be called "External Command n" where 'n' is the external menu item tool location in the external menu items group of the Tools menu
- Open "Tools=>Customize" dialog.
- Select "Context Menus" in the "Toolbars" tab.
- The context menus will appear on the toolbar. Select a context menu from one on the toolbar. Some useful ones are:
- "Project and Solution Context Menus=>Item" - This is the file context menu in the solutions folder
- "Project and Solution Context Menus=>Project" - This is the project context menu in the solutions folder
- "Other Context Menus=>Easy MDI Document Window" - Not obvious. This is the context menu for the tab at the top of a file editor window
- Goto "Command" tab and select "Tools" in the categories tab. From the "Commands:" list select the appropriate "External Command n"
Title: P4 Checkout
Command: C:\Program Files (x86)\Perforce\p4.exe
Arguments: edit $(ItemPath)
Initial Directory: $(ItemDir)
Select "Use Output window"
As shown here:
Title: P4 Revert
Command: C:\Program Files (x86)\Perforce\p4.exe
Arguments: revert $(ItemPath)
Initial Directory: $(ItemDir)
Select "Use Output window"
June 29, 2010
Open An EMail In Outlook
If are running a PC with Outlook and you want to open an email using Outlook from your application (but not send it immediately)
Following sample opens an email dialog with a specified document already attached
Following sample opens an email dialog with a specified document already attached
private void butEMailFiles_Click(object sender, RoutedEventArgs e) { string archiveName = GetExistingArchiveName(); if (File.Exists(archiveName)) { RunShellCommand("Outlook.exe", "/a \"" + archiveName + "\""); } } private static void RunShellCommand(string app, string args) { string dir = System.IO.Path.GetDirectoryName(app); string file = System.IO.Path.GetFileName(app); Process process = new Process(); process.StartInfo.FileName = file; process.StartInfo.WorkingDirectory = dir; process.StartInfo.Arguments = args; process.Start(); }
Run Batch File in C#
Quick method to create and run a batch file, the contents of which are passed as a string.
private void RunBatchFile( string batFileContents, int waitToFinishSecs) { string batFile = Path.GetTempFileName(); batFile = batFile.Replace(".tmp", ".bat"); File.WriteAllText(batFile, batFileContents); string dir = System.IO.Path.GetDirectoryName(batFile); string file = System.IO.Path.GetFileName(batFile); Process process = new Process(); process.StartInfo.FileName = file; process.StartInfo.WorkingDirectory = dir; bool res = false; // Dont do anything with this yet try { process.Start(); res = process.WaitForExit(waitToFinishSecs*1000); File.Delete(batFile); } catch (Win32Exception winex) { Debug.WriteLine(winex.ToString()); throw; } }
June 10, 2010
Sweepstake Generator
Highly topical now the world cup is on!
Here is my sweepstake generator class
class SweepstakeGenerator { public class PlayerTeamPair { public string Player { get; set; } public string Team { get; set; } public override string ToString() { return (string.IsNullOrEmpty(Team) || string.IsNullOrEmpty(Player)) ? "" : Team + " - " + Player; } } public static IEnumerableand sample usageAssignTeams( IEnumerable orderedTeams, IEnumerable namesArray) { Debug.Assert(namesArray.Count() > 0, "No names in the names array!"); List names = new List (); List teams = new List (orderedTeams); List assignedTeams = new List (teams.Count); Random random = new Random(); int teamIx = 0; while (teamIx < teams.Count) { if (names.Count == 0) { names = names = new List (namesArray); } int nameIx = random.Next(0, names.Count); assignedTeams.Add(new PlayerTeamPair() { Team = teams[teamIx], Player = names[nameIx] }); //Debug.WriteLine(teams[teamIx] + " - " + names[nameIx]); //Console.WriteLine(teams[teamIx] + " - " + names[nameIx]); names.RemoveAt(nameIx); teamIx++; } return assignedTeams; } }
string[] teamsOrderedByBettingOdds = new string[] { "Spain", "Brazil", "Argentina", "England", "Holland", "Germany", "Italy", "France", "Portugal", "Ivory Coast", "Serbia", "Mexico", "Chile", "USA", "Paraguay", "Uruguay", "Cameroon", "South Africa", "Ghana", "Australia", "Denmark", "Nigeria", "Greece", "South Korea", "Switzerland", "Slovakia", "Slovenia", "Japan", "Algeria", "Honduras", "North Korea", "New Zealand" }; string[] teamsOrderedByGrouping = new string[] { "France", "Mexico", "South Africa", "Uruguay", "Argentina", "Greece", "Nigeria", "South Korea", "Algeria", "England", "Slovenia", "USA", "Australia", "Germany", "Ghana", "Serbia", "Cameroon", "Denmark", "Japan", "Netherlands", "Italy", "New Zealand", "Paraguay", "Slovakia", "Brazil", "Ivory Coast", "North Korea", "Portugal", "Chile", "Honduras", "Spain", "Switzerland" }; string[] teamsOrderedTop8AndThenByGrouping = new string[] { "France", "Argentina", "England", "Germany", "Holland", "Italy", "Brazil", "Spain", "Mexico", "South Africa", "Uruguay", "Greece", "Nigeria", "South Korea", "Algeria", "Slovenia", "USA", "Australia", "Ghana", "Serbia", "Cameroon", "Denmark", "Japan", "New Zealand", "Paraguay", "Slovakia", "Ivory Coast", "North Korea", "Portugal", "Chile", "Honduras", "Switzerland" }; string[] namesArray = new string[] { "Bob", "Ron", "Tony", "Jim", "George", "Ben", "Alf", "Dirk" }; IEnumerableSample OutputplayerTeamIter = SweepstakeGenerator.AssignTeams( teamsOrderedTop8AndThenByGrouping, namesArray); foreach (SweepstakeGenerator.PlayerTeamPair playerTeam in playerTeamIter) { Debug.WriteLine(playerTeam.ToString()); }
France - George Argentina - Tony England - Alf Germany - Ron Holland - Bob Italy - Jim Brazil - Ben Spain - Dirk Mexico - Jim South Africa - Ben Uruguay - George Greece - Dirk Nigeria - Alf South Korea - Ron Algeria - Bob Slovenia - Tony USA - Dirk Australia - Jim Ghana - Alf Serbia - George Cameroon - Tony Denmark - Ben Japan - Ron New Zealand - Bob Paraguay - Dirk Slovakia - Alf Ivory Coast - Jim North Korea - Ben Portugal - Ron Chile - Bob Honduras - George Switzerland - Tony
May 28, 2010
Send An Email Using Outlook
See KB Article 310263
Add a reference to Microsoft.Office.Interop.Outlook then use following code:
Add a reference to Microsoft.Office.Interop.Outlook then use following code:
using Outlook = Microsoft.Office.Interop.Outlook; public void SendPlainFormatEmail( string recipient, string subject, string body, string filePath, bool silently) { try { //Check file exists before the method is called FileInfo fi = new FileInfo(filePath); bool exists = fi.Exists; if (!exists) return; string fileName = fi.Name; // Create the Outlook application by using inline initialization. Outlook.Application outlookApp = new Outlook.Application(); //Create the new message by using the simplest approach. Outlook.MailItem msg = (Outlook.MailItem)outlookApp.CreateItem( Outlook.OlItemType.olMailItem); Outlook.Recipient outlookRecip = null; //Add a recipient. if (!string.IsNullOrEmpty(recipient)) { outlookRecip = (Outlook.Recipient)msg.Recipients.Add(recipient); outlookRecip.Resolve(); } //Set the basic properties. msg.Subject = subject; msg.Body = body; msg.BodyFormat = Microsoft.Office.Interop.Outlook. OlBodyFormat.olFormatPlain; //Add an attachment. long sizeKB = fi.Length / 1024; string sDisplayName = fileName + "(" + sizeKB.ToString() + " KB)"; int position = (int)msg.Body.Length + 1; int iAttachType = (int)Outlook.OlAttachmentType.olByValue; Outlook.Attachment attachment = msg.Attachments.Add( filePath, iAttachType, position, sDisplayName); //msg.Save(); if (silently) { //Send the message. msg.Send(); } else { msg.Display(true); //modal } //Explicitly release objects. outlookRecip = null; attachment = null; msg = null; outlookApp = null; } // Simple error handler. catch (Exception e) { Console.WriteLine("{0} Exception caught: ", e); } }Following code uses the above method to email a file:
public void EmailFile(string recipient, string filePath) { FileInfo fi = new FileInfo(filePath); bool exists = fi.Exists; if (!exists) return; string fileName = fi.Name; string subject = "Emailing: " + fileName; string body = "Your message is ready to be sent with the following " "file or link attachments:" + Environment.NewLine + Environment.NewLine + fileName + Environment.NewLine + Environment.NewLine + "Note: To protect against computer viruses, e-mail programs" " may prevent sending or receiving certain types of file " "attachments. Check your e-mail security settings to determine" " how attachments are handled."; ; SendPlainFormatEmail(recipient, subject, body, filePath, false); }
May 27, 2010
WPF MessageBox Dialog Examples
Copy and paste type samples
using System.Windows;Suprise type dialog:
MessageBox.Show(this, "Specified root directory \'" + rootDir + "\'does not exist", "Find files", MessageBoxButton.OK, MessageBoxImage.Exclamation);Question type dialog:
MessageBox.Show(this, "Are you sure you want to delete these files" + Environment.NewLine + fileListStr, "Delete selected files", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
May 26, 2010
Beware of using anonymous delegates for event handlers
First found a description of this issue here
There is a problem unsubscribing to an event
Check out the following code:
There is a problem unsubscribing to an event
Check out the following code:
EventHandleronXXX = delegate(object sender, XXXEventArgs e) { onXXXCallCount++; xxxs.Add(e.LastXXX); }; ... m_YYY.OnXXX += onXXX; ... // The anonymous event handler stays on the event handler until removed // or the parent object is disposed of! m_YYY.OnXXX -= onXXX;
May 20, 2010
Open Explorer At Some Directory in C#
Use the following code snippet:
// Open explorer in user temporary directory OpenExplorerInDir(System.IO.Path.GetTempPath()); ... private void OpenExplorerInDir(string dir) { string exe = "explorer.exe"; //Driectory.Exists Process exeProcess = new Process(); exeProcess.StartInfo.FileName = exe; exeProcess.StartInfo.Arguments = "/e,/root," + dir; exeProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal; exeProcess.Start(); }
C++ Pattern: Use pointer behind a reference
The advantage is in the header file the member variable is forward declared so the user of the class only needs the header file in their class source file (and not in their header)
In header file declare the reference object:
... namespace aaaa { namespace bbbb { class xxxx; }} ... /// Reference member variable. aaaa::bbbb::xxxx& memberVar;In source file assign reference using *new()
SomeClass::SomeClass(const SomeClass &time) // Here is the trick, new() and dereference (*) // immediately into a reference object : memberVar(*new xxxx(time.memberVar)) { } SomeClass::~SomeClass() { delete &memberVar; }
Null Pointers and Delete in C++
From here: Null Pointers and Delete
C++ guarantees that delete operator checks its argument for null-ness. If the argument is 0, the delete expression has no effect. In other words, deleting a null pointer is a safe (yet useless) operation.
if (ptr == NULL) // useless, delete already checks for null value { delete(ptr); } // but always set ptr = NULL after deleting it otherwise another // call to delete(ptr) will throw an exception ptr = NULL;
C++ Virtual Destructor
Look at this Why are destructors not virtual by default?
Basic rule is if a class has at least one virtual function, it should have a virtual destructor
Example:
Example:
class Base { ... virtual ~Base(); ... }; class Derived : public Base { ... ~Derived(); };
C++ auto_ptr and shared_ptr
std::auto_ptr
Good article on why and how to use it Another good article on when and how to use it{ auto_ptr<T> ptr( new T ); ... } // when ptr goes out of scope it deletes the underlying object!
- auto_ptr employs the "exclusive ownership" model. This means that you can't bind more than one auto_ptr object to the same resource.
- Be careful when passing as a parameter to a method by value because on returning the pointer will point to nothing. The copy in the method will destroy the pointer when the method ends, so pass it by reference.
- Also because of this do not use it with template libraries!
std::tr1::shared_ptr
- Unlike auto_ptr, shared_ptr uses reference counting so multiple "shared_ptr"s can point to the same resource.
- Destructor decrement the reference count. When it reaches zero the resource is "delete"d.
- Can have a user defined deleter, so shared_ptr need not necessarily hold a "pointer to something" type resource, it could be a file handle, etc. Define a "delete" function to delete the custom resource
- Be careful of cyclic references, the objects will not be able to delete one another
May 14, 2010
Example Using std::map<> In C++
See Wikipedia reference
std::map<XXX*, DataAveragerPtr> averagerCache; const XXX* xxx = ... DataAveragerPtr averager; if(averagerCache.find(xxx) == averagerCache.end()) { // Not found so create a new one averager.reset(new SomeDataAverager(...)); averager->DoSomethingExpensive(); averagerCache.insert (std::pair<XXX*, DataAveragerPtr>( xxx, averager)); } else // found it { // for parametric types <A, B> use an A to get a B, // B b = mymap[a]; where a is of type A averager = averagerCache[xxx]; // lookup } ... if (!averagerCache.empty()) averagerCache.clear();When passing it as a parameter, the best option is to pass it by reference and just create it on the stack.
Events In C#
Look here: How to: Implement Events in Your Class - A good beginners guide.
and here: C# events vs. delegates - Good detailed explanation of events and how they differ from delegates
Also in Windows Forms programs events often lead to memory leaks as the events were never detached seehere
Note that the event source is called the "Event Publisher", ie. it is the class containg the event definition. The event target or "Subscriber" is the object attaching a delegate to the event. Be careful with C# events and the Garbage Collection of unreferenced objects. A C# event publisher holds a reference to the subscriber so the Subscriber cannot be disposed of until that event is detached (or there is no longer a reference to either the publisher or subscriber). This also means that if the subscriber has a Dispose event, you cannot rely on the system to invoke it in a GC round until that event is detached. If you attach a subscriber on to the event of a publisher, ensure it is detached
and here: C# events vs. delegates - Good detailed explanation of events and how they differ from delegates
Implementing the event in Your Publisher Class
Step 1 (Optional): Define your custom "EventArgs" classpublic class SomethingChangedEventArgs : EventArgs { ... }The following steps take place in the event publisher class
class SomethingChangedEventPublisher {Step 2: Expose your custom EventHandler
public event EventHandler<SomethingChangedEventArgs> SomethingChanged; // for events with custom arguments public event EventHandler SomethingChanged; // otherwise use this for standard eventsStep 3: Define an event publishing helper method (this is agood practice)
void PublishSomethingChangedEvent(SomethingChangedEventArgs ea) { EventHandler<SomethingChangedEventArgs> eh = this.SomethingChanged if (eh != null) eh(this, ea); }Step 4: Publish/Fire/Trigger the event in the appropriate places
... PublishSomethingChangedEvent(this, new SomethingChangedEventArgs(...)); ... }
Subscribing to the event in the Listener/Observer/Subscriber Class
The following steps take place in the event observer/subscriber classclass SomethingChangedEventSubscriber {Step 5: Subscribe to the event
// VS Intellisense will do most of the work for you here! SomethingChangedEventSource.SomethingChanged += new EventHandler<SomethingChangedEventArgs>(OnSomethingChanged); ...Step 6: Handle the event
// The method where the SomethingChangedEvent is processed private void OnSomethingChanged(object sender, SomethingChangedEventArgs eargs) { // SomethingChanged detected, now do something with it here } ...Step 7: Unsubscribe to the event. This is in my experience the biggest cause of memory leaks in C# programs
// VS Intellisense will do most of the work for you here! SomethingChangedEventSource.SomethingChanged -= new EventHandler<SomethingChangedEventArgs>(OnSomethingChanged); ... }Alternatively, use an inline delegate to handle the event
SomethingChangedEventSource.SomethingChanged += delegate (object sender, SomethingChangedEventArgs e) { ... };But there is a danger to doing this see here
Also in Windows Forms programs events often lead to memory leaks as the events were never detached seehere
Note that the event source is called the "Event Publisher", ie. it is the class containg the event definition. The event target or "Subscriber" is the object attaching a delegate to the event. Be careful with C# events and the Garbage Collection of unreferenced objects. A C# event publisher holds a reference to the subscriber so the Subscriber cannot be disposed of until that event is detached (or there is no longer a reference to either the publisher or subscriber). This also means that if the subscriber has a Dispose event, you cannot rely on the system to invoke it in a GC round until that event is detached. If you attach a subscriber on to the event of a publisher, ensure it is detached
May 12, 2010
Creating A Single Instance WPF Application
Look here:
Initial idea. - Did not seem to work!
How can I provide my own Main() method in my WPF application?
and here
Simplest solution found:
How can I provide my own Main() method in my WPF application?
and here
Simplest solution found:
- On App.xaml build properties, set "Build Action" to Page.
- Add following code to "App.xml.cs" or equivalent, the "App" class source.
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; using System.Windows; ... [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); /// <summary> /// Application Entry Point. /// </summary> [System.STAThreadAttribute()] [System.Diagnostics.DebuggerNonUserCodeAttribute()] public static void Main() { // Use mutex to ensure only single instance is running bool mutexOwnershipGranted = true; using (Mutex mutex = new Mutex( true, "$SOMEUNIQUESTRING$", // Use GUID or string id here out mutexOwnershipGranted)) { // If this is the only running instance if (mutexOwnershipGranted) { // Then run app DevHelperWpf.App app = new DevHelperWpf.App(); app.InitializeComponent(); app.Run(); } else { // Bring current running instance to the front Process current = Process.GetCurrentProcess(); foreach (Process process in Process.GetProcessesByName( current.ProcessName)) { if (process.Id != current.Id) { SetForegroundWindow(process.MainWindowHandle); break; } } } } }
Labels:
Main,
Single instance application,
WPF
March 24, 2010
Environment Variables
Environment.SetEnvironmentVariable Method on MSDN provides some comprehensive samples
Use of "Environment.GetEnvironmentVariables()" Example:
Use of "Environment.GetEnvironmentVariables()" Example:
... ShowEnvironmentVariables(EnvironmentVariableTarget.User); ShowEnvironmentVariables(EnvironmentVariableTarget.Machine); ShowEnvironmentVariables(EnvironmentVariableTarget.Process); ... private static void ShowEnvironmentVariables(EnvironmentVariableTarget targ) { IDictionary ret = Environment.GetEnvironmentVariables(targ); string[] keys = new string[ret.Count]; string[] values = new string[ret.Count]; ret.Keys.CopyTo(keys, 0); ret.Values.CopyTo(values, 0); string targStr = targ.ToString().ToUpper(); string underlineStr = "======="; Debug.WriteLine(targStr); Debug.WriteLine(underlineStr); for (int ix = 0; ix < ret.Count; ix++) { Console.WriteLine(keys[ix] + " = " + values[ix]); } Debug.WriteLine(""); }To write an Environment variable use "Environment.SetEnvironmentVariable"
// by default the environment variable is set on the "Process" Environment.SetEnvironmentVariable("TestEnvVar", "change1"); // but can be set for the user Environment.SetEnvironmentVariable("TestEnvVar", "andagain", EnvironmentVariableTarget.User); // or the system (if the program is executed through an account // with the appropriate permissions) Environment.SetEnvironmentVariable("TestEnvVar", "andagain", EnvironmentVariableTarget.Machine);
February 16, 2010
ZipStorer
Quick way to include Zip file functionality.
Find up to date version at http://zipstorer.codeplex.com/
The nice thing about ZipStorer is that you dont need to reference any other assemblies, you just include the class file in your project and away you go.
Quick and dirty example of using ZipStorer to compress a bunch of files:
Find up to date version at http://zipstorer.codeplex.com/
The nice thing about ZipStorer is that you dont need to reference any other assemblies, you just include the class file in your project and away you go.
Quick and dirty example of using ZipStorer to compress a bunch of files:
... saveFilePath = System.IO.Path.ChangeExtension(saveFilePath, "zip"); StringBuilder fileList = new StringBuilder(); string comment = "File changes from: " + DateTime.UtcNow.ToLongDateString() + Environment.NewLine + "Original path: " + rootDir; using (ZipStorer zipStore = ZipStorer.Create(saveFilePath, comment)) { foreach (CheckedListItem cli in listBoxFilesChanged.SelectedItems) { if (cli.FileSystemInfo.Exists) { zipStore.AddFile(ZipStorer.Compression.Deflate, // Compress cli.FullName, // Full path of file to be added cli.RelativeName, // Stored as a relative path in zip file cli.FullName); // Comment for stored file (source of the original) fileList.AppendLine(cli.FullName); } } } ...
Show and ShowDialog in WPF
Show a WPF window in modal form use ShowDialog()
private void ShowXXXDialogModal() { // Instantiate the dialog box XXXDlg dlg = new XXXDlg(); // Configure the dialog box dlg.Owner = this; // Open the dialog box modally dlg.ShowDialog(); }Show a WPF window in modaless form (ie dont wait for the opened window to close before returning) use Show()
private void ShowXXXDialogModaless() { // Instantiate the dialog box XXXDlg dlg = new XXXDlg(); // Configure the dialog box dlg.Owner = this; // Open the dialog box modalessly dlg.Show(); }
February 9, 2010
Dialog To Browse For A Folder
Need these refences
using System.Windows.Forms; using System.IO;Sample button logic
private void butBrowse_Click(object sender, RoutedEventArgs e) { tbRootDir.Text = BrowseForFolder("Browse to root directory of source", tbRootDir.Text); }Browser dialog usage:
private string BrowseForFolder(string descr, string dir) { using (FolderBrowserDialog fbd = new FolderBrowserDialog()) { fbd.Description = descr; if (Directory.Exists(dir)) fbd.SelectedPath = dir; if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { if (Directory.Exists(fbd.SelectedPath)) { dir = fbd.SelectedPath; } } } return dir; }
January 27, 2010
Generic Constraints Syntax In C# (using where keyword)
On MSDN
or
Search for MSDN page with this
Takes the form:
The type argument must be a value type. Any value type except Nullable can be specified.
where T : class
The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
where T : new()
The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last.
where T : <base class name>
The type argument must be or derive from the specified base class.
where T : <interface name>
The type argument must be or implement the specified interface. Can be more than one and the interfaces specified can be generic
where T : U
The type argument supplied for T must be or derive from the argument supplied for U.
or
Search for MSDN page with this
Takes the form:
... class SomeClass<args>
where Args : class
Here is a list of valid constraints
where T: structThe type argument must be a value type. Any value type except Nullable can be specified.
where T : class
The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
where T : new()
The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last.
where T : <base class name>
The type argument must be or derive from the specified base class.
where T : <interface name>
The type argument must be or implement the specified interface. Can be more than one and the interfaces specified can be generic
where T : U
The type argument supplied for T must be or derive from the argument supplied for U.
January 22, 2010
Hosting WPF Controls In Windows Forms
Host WPF controls in a windows form control (using an ElementHost)
WPF for those who know Windows Forms (Large document)
You must add references to "WindowsBase", "WindowsFormsIntergration", "PresentationCore" and "PresentationFramework"
WPF for those who know Windows Forms (Large document)
You must add references to "WindowsBase", "WindowsFormsIntergration", "PresentationCore" and "PresentationFramework"
private ElementHost wpfCtrlHost; private TestWpfControl testWpfCtrl; public WindowsFormHost() { InitializeComponent(); ... HostWpfControl(); } private void HostWpfControl() { wpfCtrlHost = new ElementHost(); wpfCtrlHost.Dock = DockStyle.Fill; this.Controls.Add(wpfCtrlHost); testWpfCtrl = new TestWpfControl(); testWpfCtrl.InitializeComponent(); wpfCtrlHost.Child = testWpfCtrl; }
Subscribe to:
Posts (Atom)