<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Windows Forms Documentation Updates</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/winformsue/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/winformsue/feed.xml</link>
    <description>We&amp;#039;re the Windows Forms User Education team at Microsoft. We use this space to update folks on developments with Windows Forms docs, publishing doc updates before they&amp;#039;re published. Feel free to ask us questions about WinForms, and we&amp;#039;ll do our best to an</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:28:51 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Implementing multi-column filtering on the IBindingListView</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/implementing-multi-column-filtering-on-the-ibindinglistview</link>
      <pubDate>Mon, 19 May 2008 12:44:00 GMT</pubDate>
      <dc:creator><![CDATA[Cheryl Simmons]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2008/05/19/implementing-multi-column-filtering-on-the-ibindinglistview/</guid>
      <description><![CDATA[A couple of years ago, I a whitepaper about how to implement searching and sorting on the generic...]]></description>
      <content:encoded><![CDATA[<P>A couple of years ago, I a whitepaper about how to implement <A href="https://msdn.microsoft.com/en-us/library/aa480736.aspx" mce_href="https://msdn.microsoft.com/en-us/library/aa480736.aspx">searching and sorting on the generic BindingList</A> for data binding in Windows Forms. About the same time my colleague, Karl, wrote a whitepaper about adding <A href="https://msdn.microsoft.com/en-us/library/aa480727.aspx" mce_href="https://msdn.microsoft.com/en-us/library/aa480727.aspx">an auto-filter capability to the Windows Forms DataGridView</A> control. Karl and I had talked about bridging the gap by me writing another whitepaper about how to implement filtering on a generic <STRONG>BindingList</STRONG> by implementing the <STRONG>IBindingListView</STRONG>. Well , it took a year or so but I <EM>did</EM> write the code and the whitepaper. During the process, I made <A class="" href="https://blogs.msdn.com/winformsue/archive/2007/12/07/implementing-the-ibindinglistview-for-filtering.aspx" mce_href="https://blogs.msdn.com/winformsue/archive/2007/12/07/implementing-the-ibindinglistview-for-filtering.aspx">one blog post</A> about it, but continued to improve the code.&nbsp;Another few months have gone by, and the whitepaper is still not published, although I do have the paper and the code available on the Microsoft Download site. The download includes projects for Visual Studio 2005&nbsp; and 2008 in both VB.NET and C#. The VS 2008 versions include some unit tests as well. I am a big fan of unit testing, even though I am by no means an expert. I found the unit tests very helpful and my editor suggested I publish them because you might find them helpful as well. In addition, I've included projects that demonstrate the filtered list working the the auto-filtered <STRONG>DataGridView</STRONG>.</P>
<P>When I started on this project I honestly did not understand how complex it was. When you implement filtering one of the first things you need to decide is what sort of filtering expressions your code will accept. I opted for a sub-set of the <STRONG>DataView.RowFilter</STRONG> format guidelines. I limited my operators to &lt;,&gt; and = to keep things simple. My idea was to give you a jumping off point for more complex filtering. In addition, I opted to only filter types that implement <STRONG>IComparable</STRONG>. Attempts to filter other types will result in an exception. A complication is that I started with a list that already supports single-column sorting. This means that the sorting and filtering implementations need to play nice together. For example, a sorted collection that is later filtered should remain in the same sorted order, or if a list is sorted and filtered, and the sort is removed, it should remain filtered. </P>
<P>Following is some of the code from the paper with a brief explanation. If you want to stop reading this post and go straight to the paper and code, you can find it <A href="https://www.microsoft.com/downloads/details.aspx?FamilyID=4af0c96d-61d5-4645-8961-b423318541b4&amp;displaylang=en">here</A>.</P>
<P>The are only three APIs exposed by <STRONG>IBindingListView</STRONG> that you need to implement for filtering:</P>
<UL>
<LI><STRONG>SupportsFiltering</STRONG> property </LI>
<LI><STRONG>Filter</STRONG> property </LI>
<LI><STRONG>RemoveFilter</STRONG> method</LI></UL>
<P><STRONG>SupportsFiltering</STRONG> is simple. For my implementation this always return <STRONG>true</STRONG>. The get for the <STRONG>Filter</STRONG> property is simple as well. I simply return the value of the backing private field. The filteret is where a lot of heavy lifting happens. When the <STRONG>Filter</STRONG> property is set, the filter is applied to the collection and only items meeting the filter criteria are returned. This means you need to do a lot of work in the set:</P>
<UL>
<LI>Cache the existing collection in case the filter is removed </LI>
<LI>Check for null or empty string; this means the filter has been removed and you need to restore the original collection</LI>
<LI>Parse the filter expression to determine if its in the correct format </LI>
<LI>Apply the filter, and return on list values that meet the filter criteria </LI>
<LI>Reapply the sort if necessary</LI></UL>
<P>These steps are further complicated by multi-column filtering.</P>
<P>Here's the code from my Filter set:</P>
<P><FONT face="Courier New">set <BR>{ <BR>&nbsp;&nbsp;&nbsp; if (filterValue == value) return; </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; // If the value is not null or empty, but doesn't <BR>&nbsp;&nbsp;&nbsp; // match expected format, throw an exception. <BR>&nbsp;&nbsp;&nbsp; if (!string.IsNullOrEmpty(value) &amp;&amp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; !Regex.IsMatch(value, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BuildRegExForFilterFormat(), RegexOptions.Singleline)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ArgumentException("Filter is not in " + <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "the format: propName[&lt;&gt;=]'value'."); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; //Turn off list-changed events. <BR>&nbsp;&nbsp;&nbsp; RaiseListChangedEvents = false; </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; // If the value is null or empty, reset list. <BR>&nbsp;&nbsp;&nbsp; if (string.IsNullOrEmpty(value)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResetList(); <BR>&nbsp;&nbsp;&nbsp; else <BR>&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int count = 0; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string[] matches = value.Split(new string[] { " AND " }, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringSplitOptions.RemoveEmptyEntries); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (count &lt; matches.Length) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string filterPart = matches[count].ToString(); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Check to see if the filter was set previously. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Also, check if current filter is a subset of <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // the previous filter. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!String.IsNullOrEmpty(filterValue) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; !value.Contains(filterValue)) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ResetList(); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Parse and apply the filter. <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SingleFilterInfo filterInfo = ParseFilter(filterPart); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ApplyFilter(filterInfo); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count++; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp;&nbsp; // Set the filter value and turn on list changed events. <BR>&nbsp;&nbsp;&nbsp; filterValue = value; <BR>&nbsp;&nbsp;&nbsp; RaiseListChangedEvents = true; <BR>&nbsp;&nbsp;&nbsp; OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); <BR>}</FONT></P>
<P><FONT face=verd>As I said previously, there's a lot happening here. First I check to see if the filter value has changed, if not, I simply return. Then I check for the correct filter format by calling <STRONG><FONT face=verdana>BuildRegExForFilterFormat</FONT></STRONG>. Following is the code for this method:</FONT></P>
<P><FONT face="Courier New">// Build a regular expression to determine if <BR>// filter is in correct format. <BR>public static string BuildRegExForFilterFormat() <BR>{ <BR>&nbsp;&nbsp;&nbsp; StringBuilder regex = new StringBuilder(); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; // Look for optional literal brackets, <BR>&nbsp;&nbsp;&nbsp; // followed by word characters or space. <BR>&nbsp;&nbsp;&nbsp; regex.Append(@"\[?[\w\s]+\]?\s?"); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; // Add the operators: &gt; &lt; or =. <BR>&nbsp;&nbsp;&nbsp; regex.Append(@"[&gt;&lt;=]"); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; //Add optional space followed by optional quote and <BR>&nbsp;&nbsp;&nbsp; // any character followed by the optional quote. <BR>&nbsp;&nbsp;&nbsp; regex.Append(@"\s?'?.+'?"); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp; return regex.ToString(); <BR>}</FONT></P>
<P>If the filter is in the correct format I know I'm in business and turn off change notification so I can manipulate the contents of the list without notifying bound controls.</P>
<P>Next I check for null or an empty string. One of these values indicates the filter has been removed and I need to reset the contents of the list to the unfiltered content. Following is the code for the <STRONG>ResetList</STRONG> method. Once I restore the original list, I reapply the sort, if the list is sorted.</P>
<P><FONT face="Courier New">private void ResetList() <BR>{ <BR>&nbsp;&nbsp;&nbsp; this.ClearItems(); <BR>&nbsp;&nbsp;&nbsp; foreach (T t in originalListValue) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Items.Add(t); <BR>&nbsp;&nbsp;&nbsp; if (IsSortedCore) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ApplySortCore(SortPropertyCore, SortDirectionCore); <BR>}</FONT></P>
<P>Next I split the filter at "AND" to separate the parts of a multi-column filter. I loop through each filter part and parse and apply the filter to the list. I do some checking to see if the current filter part is a subset of a previous filter indicating a portion of a multi-column filter is being removed. In this case, I reset the list before I apply the filter. I created the <STRONG>SingleFilterInfo</STRONG> and <STRONG>FilterOperator</STRONG> enums to aid in parsing and filtering. The actual parsing and filtering are done by the <STRONG>ParseFilter</STRONG> and <STRONG>ApplyFilter</STRONG> methods. Following is the code for&nbsp; these methods along with the enums and supporting methods.</P>
<P><FONT face="Courier New">internal void ApplyFilter(SingleFilterInfo filterParts) <BR>{ <BR>&nbsp;&nbsp;&nbsp; List&lt;T&gt; results; </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; // Check to see if the property type we are filtering by implements <BR>&nbsp;&nbsp;&nbsp; // the IComparable interface. <BR>&nbsp;&nbsp;&nbsp; Type interfaceType = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeDescriptor.GetProperties(typeof(T))[filterParts.PropName] <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .PropertyType.GetInterface("IComparable"); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; if (interfaceType == null) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new InvalidOperationException("Filtered property" + <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " must implement IComparable."); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; results = new List&lt;T&gt;(); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; // Check each value and add to the results list. <BR>&nbsp;&nbsp;&nbsp; foreach (T item in this) <BR>&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (filterParts.PropDesc.GetValue(item) != null) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IComparable compareValue = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterParts.PropDesc.GetValue(item) as IComparable; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int result = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; compareValue.CompareTo(filterParts.CompareValue); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (filterParts.OperatorValue == <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterOperator.EqualTo &amp;&amp; result == 0) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; results.Add(item); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (filterParts.OperatorValue == <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterOperator.GreaterThan &amp;&amp; result &gt; 0) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; results.Add(item); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (filterParts.OperatorValue == <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterOperator.LessThan &amp;&amp; result &lt; 0) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; results.Add(item); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp;&nbsp; this.ClearItems(); <BR>&nbsp;&nbsp;&nbsp; foreach (T itemFound in results) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Add(itemFound); <BR>} </FONT></P>
<P><FONT face="Courier New">internal SingleFilterInfo ParseFilter(string filterPart) <BR>{ <BR>&nbsp;&nbsp;&nbsp; SingleFilterInfo filterInfo = new SingleFilterInfo(); <BR>&nbsp;&nbsp;&nbsp; filterInfo.OperatorValue = DetermineFilterOperator(filterPart); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; string[] filterStringParts = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterPart.Split(new char[] { (char)filterInfo.OperatorValue }); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; filterInfo.PropName = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterStringParts[0].Replace("[", ""). <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Replace("]", "").Replace(" AND ", "").Trim(); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; // Get the property descriptor for the filter property name. <BR>&nbsp;&nbsp;&nbsp; PropertyDescriptor filterPropDesc = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeDescriptor.GetProperties(typeof(T))[filterInfo.PropName]; </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; // Convert the filter compare value to the property type. <BR>&nbsp;&nbsp;&nbsp; if (filterPropDesc == null) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new InvalidOperationException("Specified property to " + <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "filter " + filterInfo.PropName + <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " on does not exist on type: " + typeof(T).Name); </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; filterInfo.PropDesc = filterPropDesc; </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; string comparePartNoQuotes = StripOffQuotes(filterStringParts[1]); <BR>&nbsp;&nbsp;&nbsp; try <BR>&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeConverter converter = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeDescriptor.GetConverter(filterPropDesc.PropertyType); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterInfo.CompareValue = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; converter.ConvertFromString(comparePartNoQuotes); <BR>&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp;&nbsp; catch (NotSupportedException) <BR>&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new InvalidOperationException("Specified filter" + <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "value " + comparePartNoQuotes + " can not be converted" + <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "from string. Implement a type converter for " + <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterPropDesc.PropertyType.ToString()); <BR>&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp;&nbsp; return filterInfo; <BR>} </FONT></P>
<P><FONT face="Courier New">internal FilterOperator DetermineFilterOperator(string filterPart) <BR>{ <BR>&nbsp;&nbsp;&nbsp; // Determine the filter's operator. <BR>&nbsp;&nbsp;&nbsp; if (Regex.IsMatch(filterPart, "[^&gt;^&lt;]=")) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FilterOperator.EqualTo; <BR>&nbsp;&nbsp;&nbsp; else if (Regex.IsMatch(filterPart, "&lt;[^&gt;^=]")) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FilterOperator.LessThan; <BR>&nbsp;&nbsp;&nbsp; else if (Regex.IsMatch(filterPart, "[^&lt;]&gt;[^=]")) <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FilterOperator.GreaterThan; <BR>&nbsp;&nbsp;&nbsp; else <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FilterOperator.None; <BR>} </FONT></P>
<P><FONT face="Courier New">internal static string StripOffQuotes(string filterPart) <BR>{ <BR>&nbsp;&nbsp;&nbsp; // Strip off quotes in compare value if they are present. <BR>&nbsp;&nbsp;&nbsp; if (Regex.IsMatch(filterPart, "'.+'")) <BR>&nbsp;&nbsp;&nbsp; { <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int quote = filterPart.IndexOf('\''); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterPart = filterPart.Remove(quote, 1); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quote = filterPart.LastIndexOf('\''); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterPart = filterPart.Remove(quote, 1); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterPart = filterPart.Trim(); <BR>&nbsp;&nbsp;&nbsp; } <BR>&nbsp;&nbsp;&nbsp; return filterPart; <BR>} </FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>public struct SingleFilterInfo <BR>{ <BR>&nbsp;&nbsp;&nbsp; internal string PropName; <BR>&nbsp;&nbsp;&nbsp; internal PropertyDescriptor PropDesc; <BR>&nbsp;&nbsp;&nbsp; internal Object CompareValue; <BR>&nbsp;&nbsp;&nbsp; internal FilterOperator OperatorValue; <BR>} </FONT></P>
<P><FONT face="Courier New">// Enum to hold filter operators. The chars <BR>// are converted to their integer values. <BR>public enum FilterOperator <BR>{ <BR>&nbsp;&nbsp;&nbsp; EqualTo = '=', <BR>&nbsp;&nbsp;&nbsp; LessThan = '&lt;', <BR>&nbsp;&nbsp;&nbsp; GreaterThan = '&gt;', <BR>&nbsp;&nbsp;&nbsp; None = ' ' <BR>}</FONT></P>
<P><FONT face="Courier New"></FONT></P>
<P>There's a lot in my paper that I am leaving out of this post. Hopefully, I've whet your appetite and you'll download the code and paper. The paper is included as part of the zip file. You can get it all here: <A href="https://www.microsoft.com/downloads/details.aspx?FamilyID=4af0c96d-61d5-4645-8961-b423318541b4&amp;displaylang=en" mce_href="https://www.microsoft.com/downloads/details.aspx?FamilyID=4af0c96d-61d5-4645-8961-b423318541b4&amp;displaylang=en">Implementing Filtering for Windows Forms Data Binding</A>. Enjoy!</P>]]></content:encoded>
    </item>
    <item>
      <title>DataGridView Watermark Cell</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/datagridview-watermark-cell</link>
      <pubDate>Wed, 02 Jan 2008 18:43:00 GMT</pubDate>
      <dc:creator><![CDATA[Karl Erickson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2008/01/02/datagridview-watermark-cell/</guid>
      <description><![CDATA[I returned from my end-of-the-year vacation to find the following reader comment in my inbox:&gt; I...]]></description>
      <content:encoded><![CDATA[<P>I returned from my end-of-the-year vacation to find the following reader comment in my inbox:<BR>&gt; I am trying to create a custom DGV column that will show a watermark for the empty cells , in the same manner like windows live search box ... any advice?</P>
<P>In case you are not familiar with this behavior, a watermark is typically a bit of help text that appears in a text box when it is "empty". For example, the search box in the upper-right corner of IE7 says "Live Search" by default, and the <A class="" href="https://msdn2.microsoft.com/en-us/library/default.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/default.aspx">MSDN Library</A> search box says "Search MSDN with Live Search". Typically, the text is in italics or is grey to differentiate it from an ordinary textbox value. As soon as you click in the text box, the help text disappears so that you can type your search terms without distraction. </P>
<P>This seemed like an interesting challenge, so I implemented the DataGridViewWatermarkCell and DataGridViewWatermarkColumn classes shown at the end of this post. All the action is in the cell's Paint method. The main bit of code just sets the <EM>formattedValue</EM> parameter in the Paint method to the watermark text and tweaks the cell styles. </P>
<P>Of course, the watermark code is only used at run time when there is no cell value, the watermark text has been set, and the cell is not in edit mode. The first part of the&nbsp;<EM>if</EM> statement in the cell Paint method prevents painting issues in the designer:</P>
<BLOCKQUOTE>
<P><FONT color=#0000ff size=2>if</FONT><FONT size=2> ((OwningColumn.Site == </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2> || !OwningColumn.Site.DesignMode) &amp;&amp; ...</FONT></P></BLOCKQUOTE>
<P><FONT size=2>It appears that the OwningColumn only has a Site in design mode, but I included the DesignMode check to make the code more readable. </FONT>The rest of the <EM>if</EM> statement checks for edit mode (but only if the cell's row is not shared - in which case RowIndex == -1), checks whether the watermark text has been set, and checks whether there is a cell value (using GetValue in case the row is shared).</P>
<P>There are a few other tasks needed to make the code usable in the Visual Studio designer. The column class, for example, is simply a column specialized to use watermark cells by default, and enables&nbsp;you to use the designer to add a watermark column and set the WatermarkText property. Like all specialized DataGridView column types, setting the property at the column level propogates the value to the cell template and to all existing cells in that column. You can override the column value for individual cells by setting the cell WatermarkText property only&nbsp;<EM>after</EM> you set the column property. </P>
<P>Another important designer consideration is the cell's Clone method override. You must override Clone to copy the WatermarkText value. If you leave out the Clone method, you can change the column WatermarkText value in the designer, but the value won't stick. Note that the column does not have to override Clone because the column always gets its WatermarkText value from the template cell.&nbsp;The cell's Clone method does the work for both the cell and the column.</P>
<P><FONT size=2>So there you have it! Clearly, this is a primitive implementation, but it should give you the basic idea if you want to take it further. For example, you might want to make more of the watermark properties (such as styles) available to the client programmer, or allow an <STRONG>Image</STRONG> watermark.</FONT></P>
<P><FONT size=2>Enjoy!</FONT></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes">using</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"> System;<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes">using</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"> System.ComponentModel;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes">using</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"> System.Drawing;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes">using</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"> System.Windows.Forms;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes">namespace</SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"> DataGridViewWatermark<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes">{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">class</SPAN> <SPAN style="COLOR: #2b91af">DataGridViewWatermarkColumn</SPAN> : <SPAN style="COLOR: #2b91af">DataGridViewTextBoxColumn<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> DataGridViewWatermarkColumn()<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>CellTemplate = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN>();<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: #2b91af">String</SPAN> WatermarkText<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">get<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">if</SPAN> (((<SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN>)CellTemplate) == <SPAN style="COLOR: blue">null</SPAN>)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: blue">throw</SPAN> <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">InvalidOperationException</SPAN>(<SPAN style="COLOR: #a31515">"cell template required"</SPAN>);<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">return</SPAN> ((<SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN>)CellTemplate).WatermarkText;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">set<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">if</SPAN> (<SPAN style="COLOR: blue">this</SPAN>.WatermarkText != <SPAN style="COLOR: blue">value</SPAN>)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>((<SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN>)CellTemplate).WatermarkText = <SPAN style="COLOR: blue">value</SPAN>;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">if</SPAN> (<SPAN style="COLOR: blue">this</SPAN>.DataGridView != <SPAN style="COLOR: blue">null</SPAN>)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">DataGridViewRowCollection</SPAN> dataGridViewRows =<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">this</SPAN>.DataGridView.Rows;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">int</SPAN> rowCount = dataGridViewRows.Count;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">for</SPAN> (<SPAN style="COLOR: blue">int</SPAN> rowIndex = 0; rowIndex &lt; rowCount; rowIndex++)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">DataGridViewRow</SPAN> dataGridViewRow =<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>dataGridViewRows.SharedRow(rowIndex);<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN> cell =<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>dataGridViewRow.Cells[<SPAN style="COLOR: blue">this</SPAN>.Index]<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">as</SPAN> <SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN>;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">if</SPAN> (cell != <SPAN style="COLOR: blue">null</SPAN>)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>cell.WatermarkText = <SPAN style="COLOR: blue">value</SPAN>;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">class</SPAN> <SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN> : <SPAN style="COLOR: #2b91af">DataGridViewTextBoxCell<o:p></o:p></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">private</SPAN> <SPAN style="COLOR: #2b91af">String</SPAN> watermarkTextValue;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: #2b91af">String</SPAN> WatermarkText<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">get</SPAN> { <SPAN style="COLOR: blue">return</SPAN> watermarkTextValue; }<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">set</SPAN> { watermarkTextValue = <SPAN style="COLOR: blue">value</SPAN>; }<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">override</SPAN> <SPAN style="COLOR: blue">object</SPAN> Clone()<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN> cell = (<SPAN style="COLOR: #2b91af">DataGridViewWatermarkCell</SPAN>)<SPAN style="COLOR: blue">base</SPAN>.Clone();<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>cell.WatermarkText = <SPAN style="COLOR: blue">this</SPAN>.WatermarkText;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: blue">return</SPAN> cell;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">protected</SPAN> <SPAN style="COLOR: blue">override</SPAN> <SPAN style="COLOR: blue">void</SPAN> Paint(<SPAN style="COLOR: #2b91af">Graphics</SPAN> graphics, <SPAN style="COLOR: #2b91af">Rectangle</SPAN> clipBounds,<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">Rectangle</SPAN> cellBounds, <SPAN style="COLOR: blue">int</SPAN> rowIndex, <SPAN style="COLOR: #2b91af">DataGridViewElementStates</SPAN> cellState,<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">object</SPAN> value, <SPAN style="COLOR: blue">object</SPAN> formattedValue, <SPAN style="COLOR: blue">string</SPAN> errorText,<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">DataGridViewCellStyle</SPAN> cellStyle,<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">DataGridViewAdvancedBorderStyle</SPAN> advancedBorderStyle,<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #2b91af">DataGridViewPaintParts</SPAN> paintParts)<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<BR></SPAN><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes"><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> ((OwningColumn.Site == </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2> || !OwningColumn.Site.DesignMode) &amp;&amp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (RowIndex &lt; 0 || !IsInEditMode) &amp;&amp; !</FONT><FONT color=#2b91af size=2>String</FONT><FONT size=2>.IsNullOrEmpty(WatermarkText) &amp;&amp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (GetValue(rowIndex) == </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2> || GetValue(rowIndex) == </FONT><FONT color=#2b91af size=2>DBNull</FONT><FONT size=2>.Value))</P></FONT></SPAN></SPAN>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>{<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>cellStyle.Font = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Font</SPAN>(cellStyle.Font, <SPAN style="COLOR: #2b91af">FontStyle</SPAN>.Italic);<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>cellStyle.ForeColor = <SPAN style="COLOR: #2b91af">Color</SPAN>.Gray;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>formattedValue = WatermarkText;<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: blue">base</SPAN>.Paint(graphics, clipBounds, cellBounds, rowIndex,<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>cellState, value, formattedValue, errorText,<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>cellStyle, advancedBorderStyle, paintParts);<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN>}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes">}<o:p></o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><o:p><FONT face="Times New Roman" size=3>&nbsp;</FONT></o:p></P>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>Client Application Services and WPF</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/client-application-services-and-wpf</link>
      <pubDate>Thu, 13 Dec 2007 17:26:00 GMT</pubDate>
      <dc:creator><![CDATA[Karl Erickson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2007/12/13/client-application-services-and-wpf/</guid>
      <description><![CDATA[Although my sample for Client Application Services (CAS) uses Windows Forms, you can adapt it to...]]></description>
      <content:encoded><![CDATA[<P>Although my <A class="" href="https://blogs.msdn.com/winformsue/attachment/2752939.ashx" mce_href="https://blogs.msdn.com/winformsue/attachment/2752939.ashx">sample</A> for <A class="" href="https://msdn2.microsoft.com/en-us/library/bb384297(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bb384297(VS.90).aspx">Client Application Services</A> (CAS) uses Windows Forms, you can adapt it to Windows Presentation Foundation (WPF) with little effort.&nbsp;The configuration steps are the same, and the client source code is the same, although some of the code would go in WPF equivalents of Windows Forms event handlers (for example, using an <STRONG>App.Startup</STRONG> or <STRONG>Window.Loaded</STRONG> event handler rather than a <STRONG>Form.Load</STRONG> event handler). </P>
<P>However, there is a peculiarity in WPF that prevents things from just working without a small adjustment. After authentication using CAS, the static <STRONG>Thread.CurrentPrincipal</STRONG> property gets set to an instance of <STRONG>ClientRolePrincipal</STRONG>. Internally, CAS checks for this value to determine whether a user is still logged in. Unfortunately, in WPF, <STRONG>Thread.CurrentPrincipal</STRONG> reverts to the default value (a <STRONG>GenericPrincipal</STRONG> instance) some time after the <STRONG>Window.Loaded</STRONG> event. </P>
<P>For details, see this <A class="" href="https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1170749&amp;SiteID=1" mce_href="https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1170749&amp;SiteID=1">forum post</A>. The fix for CAS is simple, however: just add the following line of code after your <STRONG>Membership.ValidateUser</STRONG> call in your <STRONG>App.Startup</STRONG> or <STRONG>Window.Loaded</STRONG> event handler:</P><FONT color=#2b91af size=2>
<BLOCKQUOTE>
<P>AppDomain</FONT><FONT size=2>.CurrentDomain.SetThreadPrincipal(</FONT><FONT color=#2b91af size=2>Thread</FONT><FONT size=2>.CurrentPrincipal);</FONT></P></BLOCKQUOTE>
<P><FONT size=2>At this point, <STRONG>Thread.CurrentPrincipal</STRONG> is still set to the ClientRolePrincipal object. The <STRONG>SetThreadPrincipal</STRONG> method call is what makes it stay there. </P></FONT>]]></content:encoded>
    </item>
    <item>
      <title>Implementing the IBindingListView for filtering</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/implementing-the-ibindinglistview-for-filtering</link>
      <pubDate>Fri, 07 Dec 2007 13:17:00 GMT</pubDate>
      <dc:creator><![CDATA[Cheryl Simmons]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2007/12/07/implementing-the-ibindinglistview-for-filtering/</guid>
      <description><![CDATA[Due to customer feedback and requests, I've been working on an article that demonstrates a simple...]]></description>
      <content:encoded><![CDATA[<P mce_keep="true">Due to customer feedback and requests, I've been working on an article that demonstrates a simple implementation of the filtering portion of the <B>IBindingListView</B>. This implementation works with&nbsp;the <A href="https://www.microsoft.com/downloads/details.aspx?FamilyID=bea5c31b-e07a-46b5-8662-ecd798c0134d&amp;displaylang=en" mce_href="https://www.microsoft.com/downloads/details.aspx?FamilyID=bea5c31b-e07a-46b5-8662-ecd798c0134d&amp;displaylang=en">DataGridViewAutoFilter</A> code that Karl first published in the summer of 2006 and allows you to search, sort and filter a list of business objects. In the course of writing the paper, I realized the filtering implementation could be even simpler than what I had for my article and still correctly interact with Karl's code.</P>
<P>For the simple filtering, I start with my generic implementation of searching and sorting demonstrated in my article published in summer 2006.&nbsp;I then use&nbsp;the <B>FindCore</B> method to find matches for the filter value. The code listing is lengthy so I've posted the complete listing <A href="https://blogs.msdn.com/winformsue/pages/filtering-code.aspx" target=_blank mce_href="https://blogs.msdn.com/winformsue/pages/filtering-code.aspx">here</A>.</P>
<P>That said; I want to walk you through some of the code. The filtering expression my code handles follows a subset of the guidelines established by the <B>DataColumn.Expression</B> property. I'll look for a property name followed by an equals followed by the filter value, typically&nbsp;in quotes. For example, LastName="Smith". In this simple example, I am only concerned with values equal to the filter value. My upcoming article will cover more complex filtering.</P>
<P>The <B>IBindingListView</B> interface contains three members related to filter; the <B>SupportsFiltering</B> and <STRONG>Filter</STRONG> properties as well as the <B>RemoveFilter</B> method. The first step is to implement the <B>SupportsFiltering</B> property to always return <B>true</B>.</P><FONT face=courier color=blue>
<P mce_keep="true">public bool SupportsFiltering</P>
<P>{</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; get { return true; }</P>
<P>}</P></FONT>
<P>Implementing the&nbsp;<B>Filter</B> property is more difficult and requires some preliminary steps. When the filter value is set, the filter is applied to the list and the list returns the items that meets the filter criteria. In addition, the original list must be cached because the filter can be removed, in which case, the list should revert to its original contents. Therefore, the unfiltered list is stored in a read-only property named <STRONG>UnfilteredList</STRONG>. I chose a read-only property to allow for the code to be unit-tested. The following code shows the declaration for the unfiltered list.</P><FONT face=courier color=blue>
<P mce_keep="true">List&lt;T&gt; unfilteredListValue = new List&lt;T&gt;();</P>
<P mce_keep="true">public List&lt;T&gt; UnfilteredList</P>
<P>{</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; get { return unfilteredListValue; }</P>
<P mce_keep="true">}</P>
<P mce_keep="true"></FONT>Next is the <B>Filter</B> property itself.</P>
<P mce_keep="true"><FONT face=courier color=blue>private string filterValue = null;</P>
<P mce_keep="true">public string Filter</P>
<P>&nbsp;{</P>
<P>&nbsp;&nbsp;&nbsp; ...</P>
<P>&nbsp;}</P></FONT>
<P>&nbsp;The getter for the filter property is straightforward.</P>
<P mce_keep="true"><FONT face=courier color=blue>get</P>
<P>{</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; return filterValue;</P>
<P>}</P></FONT>
<P mce_keep="true">However, the setter is more complicated and requires some explanantion. The first step in setting the <STRONG>Filter</STRONG> property is to check whether the filter value has changed. If the filter value is unchanged, the set operation should not do anything. If the Filter value has changed, I temporarily disable change notifications for the list. It is important that I do this step because I will be manipulating the contents of the list. In the context of an application, bound controls should not be notified of these internal changes. To disable change notifications, I set the <STRONG>RaiseListChangedEvents</STRONG> property to <STRONG>false</STRONG>; This property is set back to <STRONG>true</STRONG> when the set call is finished. Next, I'll check for a filter value of <STRONG>null</STRONG>. <A>Null&nbsp;</A>indicates the filter has been removed and the original list contents should be reset. I must also check the filter value to see whether it matches the expected format, which I do with a regular expression. If the filter value does not match the expected format, or the filter expression indicates multi-column filtering, an <STRONG>ArgumentException</STRONG> is thrown. If the filter complies with the expected format, I parse the filter string and apply it to the data source. Finally, I set the <STRONG>RaiseListChangedEvents</STRONG> property back to <STRONG>true</STRONG> and call raise a <STRONG>ListChanged</STRONG> event to signal bound controls to refresh. In the following code, the filter parsing and application is accomplished by two separate methods; <STRONG>GetFilterParts</STRONG> and <STRONG>ApplyFilter</STRONG>, which I'll discuss next.</P>
<P mce_keep="true"><FONT face=courier color=blue>set</P>
<P>{</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; if (filterValue != value)</P>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RaiseListChangedEvents = false;</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If filter value is null, reset list.</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (value == null)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.ClearItems();</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (T t in unfilteredListValue)</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Items.Add(t);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterValue = value;</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P mce_keep="true">&nbsp;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If the value is empty string, do nothing.</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // This behavior is compatible with DataGridView</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // AutoFilter code.</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (value == "") { }</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If the value is not null or string, than process</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // normal.</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (Regex.Matches(value,</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "[?[\\w ]+]? ?[=] ?'?[\\w|/: ]+'?",</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RegexOptions.Singleline).Count == 1)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If the filter is not set.</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unfilteredListValue.Clear();</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unfilteredListValue.AddRange(this.Items);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterValue = value;</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetFilterParts();</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ApplyFilter();</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if (Regex.Matches(value,</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "[?[\\w ]+]? ?[=] ?'?[\\w|/: ]+'?",</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RegexOptions.Singleline).Count &gt; 1)</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ArgumentException("Multi-column" +</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "filtering is not implemented.");</P>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else throw new ArgumentException("Filter is not" +</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "in the format: propName = 'value'.");</P>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RaiseListChangedEvents = true;</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; }</P>
<P mce_keep="true">}</P></FONT>
<P>In this example, parsing the filter is straightforward. I look for the "=" and grab the property name and filter value. The filter value is converted to the same type as the specified property. If the property is not found, or the conversion cannot be performed, an exception is thrown. </P>
<P>First, I expose some properties and private fields to store the filter parts.</P><FONT face=courier color=blue>
<P mce_keep="true">private string filterPropertyNameValue;</P>
<P mce_keep="true">private Object filterCompareValue;</P>
<P mce_keep="true">public string FilterPropertyName</P>
<P>{</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; get { return filterPropertyNameValue; }</P>
<P mce_keep="true">}</P>
<P mce_keep="true">public Object FilterCompare</P>
<P>{</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; get { return filterCompareValue; }</P>
<P mce_keep="true">}&nbsp;</P></FONT>
<P>Then I get the parts.</P><FONT face=courier color=blue>
<P mce_keep="true">public void GetFilterParts()</P>
<P>{</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; string[] filterParts = Filter.Split(new char[] { '=' }, </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringSplitOptions.RemoveEmptyEntries);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; filterPropertyNameValue = </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterParts[0].Replace("[", "").Replace("]", "").Trim();</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; PropertyDescriptor propDesc =</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; TypeDescriptor.GetProperties(typeof(T))[filterPropertyNameValue.ToString()];</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; if (propDesc != null)</P>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeConverter converter = TypeDescriptor.GetConverter(propDesc.PropertyType);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterCompareValue = converter.ConvertFromString(filterParts[1].Replace("'", "").Trim());</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (NotSupportedException)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ArgumentException("Specified filter value " +</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterCompare + " can not be converted from string." +</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "..Implement a type converter for " + propDesc.PropertyType.ToString());</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; }</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; else throw new ArgumentException("Specified property '" +</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterPropertyName + "' is not found on type " +</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeof(T).Name + ".");</P>
<P mce_keep="true">}</P></FONT>
<P mce_keep="true">Following is the <B>ApplyFilter</B> method. &nbsp;This method is pretty simple;&nbsp;I loop through the items using&nbsp;the <B>FindCore</B> method to get all of the matches to the filter value.</P><FONT face=courier color=blue>
<P>private void ApplyFilter()</P>
<P>{</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; unfilteredListValue.Clear();</P>
<P>&nbsp;&nbsp;&nbsp; unfilteredListValue.AddRange(this.Items);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; List&lt;T&gt; results = new List&lt;T&gt;();</P>
<P mce_keep="true">&nbsp;</P>
<P mce_keep="true">PropertyDescriptor propDesc = </P>
<P>&nbsp; TypeDescriptor.GetProperties(typeof(T))[FilterPropertyName];</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; if (propDesc != null)</P>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int tempResults = -1;</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tempResults = FindCore(tempResults + 1, propDesc, FilterCompare);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (tempResults != -1)</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; results.Add(this[tempResults]);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (tempResults != -1);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; }</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; this.ClearItems();</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; if (results != null &amp;&amp; results.Count &gt; 0)</P>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (T itemFound in results)</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Add(itemFound);</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; }</P>
<P mce_keep="true">}</P></FONT>
<P mce_keep="true">The final step is to implement <B>RemoveFilter</B>. This is simple; set <STRONG>Filter</STRONG> to <B>null</B>.</P><FONT face=courier color=blue>
<P>public void RemoveFilter()</P>
<P>{</P>
<P mce_keep="true">&nbsp;&nbsp;&nbsp; if (Filter != null) Filter = null;</P>
<P mce_keep="true">}</P></FONT>
<P>Hopefully this helps you get started with filtering and please look for my upcoming article that shows a more complex filtering implementation. </P>]]></content:encoded>
    </item>
    <item>
      <title>Filtering Code</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/filtering-code</link>
      <pubDate>Thu, 06 Dec 2007 11:50:00 GMT</pubDate>
      <dc:creator><![CDATA[Cheryl Simmons]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2007/12/06/filtering-code/</guid>
      <description><![CDATA[using System;
using System.Collections.Generic;
using System.Text;
using...]]></description>
      <content:encoded><![CDATA[<FONT face="Courier New"><FONT color=#0000ff size=2 FONT>
<P>using</FONT><FONT size=2> System;</P></FONT><FONT color=#0000ff size=2>
<P>using</FONT><FONT size=2> System.Collections.Generic;</P></FONT><FONT color=#0000ff size=2>
<P>using</FONT><FONT size=2> System.Text;</P></FONT><FONT color=#0000ff size=2>
<P>using</FONT><FONT size=2> System.ComponentModel;</P></FONT><FONT color=#0000ff size=2>
<P>using</FONT><FONT size=2> System.Windows.Forms;</P></FONT><FONT color=#0000ff size=2>
<P>using</FONT><FONT size=2> System.Text.RegularExpressions;</P></FONT><FONT color=#0000ff size=2>
<P>using</FONT><FONT size=2> System.Reflection;</P></FONT><FONT color=#0000ff size=2>
<P>using</FONT><FONT size=2> System.Collections;</P>
<P mce_keep="true">&nbsp;</P></FONT>
<P><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>class</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>SimpleFilteredList</FONT><FONT size=2>&lt;T&gt; : </FONT><FONT color=#2b91af size=2>BindingList</FONT><FONT size=2>&lt;T&gt;, </FONT><FONT color=#2b91af size=2>IBindingListView</P></FONT><FONT size=2>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; public</FONT><FONT size=2> SimpleFilteredList() {}</P>
<P mce_keep="true">&nbsp;</P></FONT><FONT color=#0000ff size=2>
<BLOCKQUOTE>
<P>#region</FONT><FONT size=2> Searching</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>bool</FONT><FONT size=2> SupportsSearchingCore</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; get</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>true</FONT><FONT size=2>;</P>
<P>&nbsp;&nbsp;&nbsp; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> FindCore(</FONT><FONT color=#2b91af size=2>PropertyDescriptor</FONT><FONT size=2> prop, </FONT><FONT color=#0000ff size=2>object</FONT><FONT size=2> key)</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; return</FONT><FONT size=2> FindCore(0, prop, key);</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> FindCore(</FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> startIndex, </FONT><FONT color=#2b91af size=2>PropertyDescriptor</FONT><FONT size=2> prop, </FONT><FONT color=#0000ff size=2>object</FONT><FONT size=2> key)</P>
<P>{</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // Get the property info for the specified property.</P></FONT><FONT size=2>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; PropertyInfo</FONT><FONT size=2> propInfo = </FONT><FONT color=#0000ff size=2>typeof</FONT><FONT size=2>(T).GetProperty(prop.Name);</P>
<P>&nbsp;&nbsp;&nbsp; T item;</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (key != </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>)</P>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // Loop through the items to see if the key</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // value matches the property value.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for</FONT><FONT size=2> (</FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> i = startIndex; i &lt; Count; ++i)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;item = (T)Items[i];</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (propInfo.GetValue(item, </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>).Equals(key))</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return</FONT><FONT size=2> i;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; return</FONT><FONT size=2> -1;</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> Find(</FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> startIndex, </FONT><FONT color=#0000ff size=2>string</FONT><FONT size=2> property, </FONT><FONT color=#0000ff size=2>object</FONT><FONT size=2> key)</P>
<P>{</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // Check the properties for a property with the specified name.</P></FONT><FONT size=2>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; PropertyDescriptorCollection</FONT><FONT size=2> properties =</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; TypeDescriptor</FONT><FONT size=2>.GetProperties(</FONT><FONT color=#0000ff size=2>typeof</FONT><FONT size=2>(T));</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; PropertyDescriptor</FONT><FONT size=2> prop = properties.Find(property, </FONT><FONT color=#0000ff size=2>true</FONT><FONT size=2>);</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;// If there is not a match, return -1 otherwise pass search to</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // FindCore method.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (prop == </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>)</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; return</FONT><FONT size=2> -1;</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; else</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; if</FONT><FONT size=2> (startIndex &lt;= 0)</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; return</FONT><FONT size=2> FindCore(prop, key);</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; else</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;return</FONT><FONT size=2> FindCore(startIndex, prop, key);</P>
<P>}</P></FONT><FONT color=#0000ff size=2>
<P>#endregion</FONT><FONT size=2> Searching</P></FONT><FONT color=#0000ff size=2>
<P>#region</FONT><FONT size=2> Sorting</P>
<P></FONT><FONT color=#2b91af size=2>ArrayList</FONT><FONT size=2> sortedList;</P>
<P></FONT><FONT color=#2b91af size=2>ArrayList</FONT><FONT size=2> unsortedItems;</P>
<P></FONT><FONT color=#0000ff size=2>bool</FONT><FONT size=2> isSortedValue;</P>
<P></FONT><FONT color=#2b91af size=2>ListSortDirection</FONT><FONT size=2> sortDirectionValue;</P>
<P></FONT><FONT color=#2b91af size=2>PropertyDescriptor</FONT><FONT size=2> sortPropertyValue;</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>bool</FONT><FONT size=2> SupportsSortingCore</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>true</FONT><FONT size=2>; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>bool</FONT><FONT size=2> IsSortedCore</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> isSortedValue; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>PropertyDescriptor</FONT><FONT size=2> SortPropertyCore</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> sortPropertyValue; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ListSortDirection</FONT><FONT size=2> SortDirectionCore</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> sortDirectionValue; }</P>
<P>}</P>
<P mce_keep="true">&nbsp;</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> ApplySort(</FONT><FONT color=#0000ff size=2>string</FONT><FONT size=2> propertyName, </FONT><FONT color=#2b91af size=2>ListSortDirection</FONT><FONT size=2> direction)</P>
<P>{</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // Check the properties for a property with the specified name.</P></FONT><FONT size=2>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; PropertyDescriptor</FONT><FONT size=2> prop = </FONT><FONT color=#2b91af size=2>TypeDescriptor</FONT><FONT size=2>.GetProperties(</FONT><FONT color=#0000ff size=2>typeof</FONT><FONT size=2>(T))[propertyName];</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // If there is not a match, return -1 otherwise pass search to</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // FindCore method.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (prop == </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>)</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; throw</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ArgumentException</FONT><FONT size=2>(propertyName + </P>
<P></FONT><FONT color=#a31515 size=2>&nbsp;&nbsp;&nbsp; " is not a valid property for type:"</FONT><FONT size=2> + </FONT><FONT color=#0000ff size=2>typeof</FONT><FONT size=2>(T).Name);</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; else</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp; ApplySortCore(prop, direction);</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> ApplySortCore(</FONT><FONT color=#2b91af size=2>PropertyDescriptor</FONT><FONT size=2> prop,</P>
<P></FONT><FONT color=#2b91af size=2>ListSortDirection</FONT><FONT size=2> direction)</P>
<P>{</P>
<P>&nbsp;&nbsp;&nbsp; RaiseListChangedEvents = </FONT><FONT color=#0000ff size=2>false</FONT><FONT size=2>;</P>
<P>&nbsp;&nbsp;&nbsp; sortedList = </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ArrayList</FONT><FONT size=2>();</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // Check to see if the property type we are sorting by implements</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // the IComparable interface.</P></FONT><FONT size=2>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; Type</FONT><FONT size=2> interfaceType = prop.PropertyType.GetInterface(</FONT><FONT color=#a31515 size=2>"IComparable"</FONT><FONT size=2>);</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (interfaceType != </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;{</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If so, set the SortPropertyValue and SortDirectionValue.</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sortPropertyValue = prop;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sortDirectionValue = direction;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsortedItems = </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ArrayList</FONT><FONT size=2>(</FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.Count);</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Loop through each item, adding it the the sortedItems ArrayList.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach</FONT><FONT size=2> (</FONT><FONT color=#2b91af size=2>Object</FONT><FONT size=2> item </FONT><FONT color=#0000ff size=2>in</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.Items)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sortedList.Add(prop.GetValue(item));</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsortedItems.Add(item);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Call Sort on the ArrayList.</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sortedList.Sort();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T temp;</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;// Check the sort direction and then copy the sorted items</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;// back into the list.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (direction == </FONT><FONT color=#2b91af size=2>ListSortDirection</FONT><FONT size=2>.Descending)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sortedList.Reverse();</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for</FONT><FONT size=2> (</FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> i = 0; i &lt; </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.Count; i++)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int</FONT><FONT size=2> position = Find(0, prop.Name, sortedList[i]);</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (position != i)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;{</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; temp = </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>[i];</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this</FONT><FONT size=2>[i] = </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>[position];</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this</FONT><FONT size=2>[position] = temp;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RaiseListChangedEvents = </FONT><FONT color=#0000ff size=2>true</FONT><FONT size=2>;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; isSortedValue = </FONT><FONT color=#0000ff size=2>true</FONT><FONT size=2>;</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Raise the ListChanged event so bound controls refresh their</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // values.</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OnListChanged(</FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ListChangedEventArgs</FONT><FONT size=2>(</FONT><FONT color=#2b91af size=2>ListChangedType</FONT><FONT size=2>.Reset, -1));</P>
<P>&nbsp; }</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp; else</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp; // If the property type does not implement IComparable, let the user</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp; // know.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp; throw</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>NotSupportedException</FONT><FONT size=2>(</FONT><FONT color=#a31515 size=2>"Cannot sort by "</FONT><FONT size=2> + prop.Name +</P>
<P></FONT><FONT color=#a31515 size=2>&nbsp; ". This"</FONT><FONT size=2> + prop.PropertyType.ToString() +</P>
<P></FONT><FONT color=#a31515 size=2>&nbsp; " does not implement IComparable"</FONT><FONT size=2>);</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>protected</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> RemoveSortCore()</P>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp; int</FONT><FONT size=2> position;</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; object</FONT><FONT size=2> temp;</P>
<P>&nbsp;&nbsp;&nbsp; RaiseListChangedEvents = </FONT><FONT color=#0000ff size=2>false</FONT><FONT size=2>;</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // Ensure the list has been sorted.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (unsortedItems != </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>)</P>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Loop through the unsorted items and reorder the</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // list per the unsorted list.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for</FONT><FONT size=2> (</FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> i = 0; i &lt; unsortedItems.Count; )</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; position = </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.Find(0, SortPropertyCore.Name,</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsortedItems[i].GetType().</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetProperty(SortPropertyCore.Name).GetValue(unsortedItems[i], </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>));</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (position &gt;= 0 &amp;&amp; position != i)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; temp = </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>[i];</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this</FONT><FONT size=2>[i] = </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>[position];</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this</FONT><FONT size=2>[position] = (T)temp;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++; </P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>if</FONT><FONT size=2> (position == i)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i++;</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If an item in the unsorted list no longer exists, delete it.</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsortedItems.RemoveAt(i);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RaiseListChangedEvents = </FONT><FONT color=#0000ff size=2>true</FONT><FONT size=2>;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OnListChanged(</FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ListChangedEventArgs</FONT><FONT size=2>(</FONT><FONT color=#2b91af size=2>ListChangedType</FONT><FONT size=2>.Reset, -1));</P>
<P>&nbsp;&nbsp;&nbsp; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> RemoveSort()</P>
<P>{</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; RemoveSortCore();</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>override</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> EndNew(</FONT><FONT color=#0000ff size=2>int</FONT><FONT size=2> itemIndex)</P>
<P>{</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp; // Check to see if the item is added to the end of the list,</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;// and if so, re-sort the list.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (sortPropertyValue != </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2> &amp;&amp; itemIndex &gt; 0 &amp;&amp; itemIndex == </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.Count - 1)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT><FONT size=2>ApplySortCore(</FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.sortPropertyValue, </FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.sortDirectionValue);</FONT></P>
<P><FONT size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT><FONT color=#0000ff size=2>base</FONT><FONT size=2>.EndNew(itemIndex);</FONT></P>
<P><FONT size=2>}</P></FONT><FONT color=#0000ff size=2>
<P>#endregion</FONT><FONT size=2> Sorting</P></FONT><FONT color=#0000ff size=2>
<P>#region</FONT><FONT size=2> AdvancedSorting</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>bool</FONT><FONT size=2> SupportsAdvancedSorting</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>false</FONT><FONT size=2>; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ListSortDescriptionCollection</FONT><FONT size=2> SortDescriptions</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>; }</P>
<P>}</P></FONT><FONT color=#0000ff size=2><FONT color=#0000ff size=2>
<P>public</FONT><FONT color=#000000 size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT color=#000000 size=2> ApplySort(</FONT><FONT color=#2b91af size=2>ListSortDescriptionCollection</FONT><FONT size=2><FONT color=#000000> sorts)</FONT></P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp; throw</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>NotImplementedException</FONT><FONT size=2>();</P>
<P>}</P>
<P></FONT></FONT><FONT color=#0000ff size=2>#endregion</FONT><FONT size=2> AdvancedSorting</P></FONT><FONT color=#0000ff size=2>
<P>#region</FONT><FONT size=2> Filtering</P>
<P></FONT><FONT color=#0000ff size=2>private</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>string</FONT><FONT size=2> filterValue = </FONT><FONT color=#a31515 size=2>""</FONT><FONT size=2>;</P>
<P></FONT><FONT color=#808080 size=2>///</FONT><FONT color=#008000 size=2> </FONT><FONT color=#808080 size=2>&lt;summary&gt;</P></FONT><FONT size=2>
<P></FONT><FONT color=#808080 size=2>///</FONT><FONT color=#008000 size=2> Should be in the format columnName ='desiredValue'</P></FONT><FONT size=2>
<P></FONT><FONT color=#808080 size=2>///</FONT><FONT color=#008000 size=2> </FONT><FONT color=#808080 size=2>&lt;/summary&gt;</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>private</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>string</FONT><FONT size=2> filterPropertyNameValue;</P>
<P></FONT><FONT color=#0000ff size=2>private</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>Object</FONT><FONT size=2> filterCompareValue;</P>
<P mce_keep="true"></FONT><FONT color=#2b91af size=2>List</FONT><FONT size=2>&lt;T&gt; unfilteredListValue = </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>List</FONT><FONT size=2>&lt;T&gt;();</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>List</FONT><FONT size=2>&lt;T&gt; UnfilteredList</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> unfilteredListValue; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>bool</FONT><FONT size=2> SupportsFiltering</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>true</FONT><FONT size=2>; }</P>
<P>}</P>
<P mce_keep="true">&nbsp;</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> RemoveFilter()</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (Filter != </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>) Filter = </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>;</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>string</FONT><FONT size=2> FilterPropertyName</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> filterPropertyNameValue; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>Object</FONT><FONT size=2> FilterCompare</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; get</FONT><FONT size=2> { </FONT><FONT color=#0000ff size=2>return</FONT><FONT size=2> filterCompareValue; }</P>
<P>}</P>
<P mce_keep="true">&nbsp;</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>string</FONT><FONT size=2> Filter</P>
<P>{</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; get</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return</FONT><FONT size=2> filterValue;</P>
<P>&nbsp;&nbsp;&nbsp; }</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; set</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#0000ff size=2>if</FONT><FONT color=#000000 size=2> (filterValue != </FONT><FONT color=#0000ff size=2>value</FONT><FONT size=2><FONT color=#000000>)</FONT></FONT></FONT></P>
<P><FONT color=#0000ff size=2><FONT size=2><FONT color=#000000>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT>{</P>
<BLOCKQUOTE>
<BLOCKQUOTE>
<P>&nbsp; RaiseListChangedEvents = </FONT><FONT color=#0000ff size=2>false</FONT><FONT size=2>;</P>
<P></FONT><FONT color=#008000 size=2>&nbsp; // If filter value is null, reset list.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp; if</FONT><FONT size=2> (</FONT><FONT color=#0000ff size=2>value</FONT><FONT size=2> == </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>)</P>
<P>&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this</FONT><FONT size=2>.ClearItems();</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach</FONT><FONT size=2> (T t </FONT><FONT color=#0000ff size=2>in</FONT><FONT size=2> unfilteredListValue)</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this</FONT><FONT size=2>.Items.Add(t);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;filterValue = </FONT><FONT color=#0000ff size=2>value</FONT><FONT size=2>;</P>
<P>&nbsp;&nbsp; }</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;// If the value is empty string, do nothing.</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp; // This behavior is compatible with DataGridView</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp; // AutoFilter code.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; else</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>if</FONT><FONT size=2> (</FONT><FONT color=#0000ff size=2>value</FONT><FONT size=2> == </FONT><FONT color=#a31515 size=2>""</FONT><FONT size=2>){}</P>
<P mce_keep="true">&nbsp;</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp; // If the value is not null or string, than process</P></FONT><FONT size=2>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp; // normal.</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; else</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>if</FONT><FONT size=2> (</FONT><FONT color=#2b91af size=2>Regex</FONT><FONT size=2>.Matches(</FONT><FONT color=#0000ff size=2>value</FONT><FONT size=2>,</P>
<P></FONT><FONT color=#a31515 size=2>&nbsp;&nbsp;&nbsp; "[?[\\w ]+]? ?[=] ?'?[\\w|/: ]+'?"</FONT><FONT size=2>,</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; RegexOptions</FONT><FONT size=2>.Singleline).Count == 1 &amp;&amp; </FONT><FONT color=#0000ff size=2>value</FONT><FONT size=2> != </FONT><FONT color=#a31515 size=2>""</FONT><FONT size=2>)</P>
<P>&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// If the filter is not set.</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unfilteredListValue.Clear();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unfilteredListValue.AddRange(</FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.Items);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterValue = </FONT><FONT color=#0000ff size=2>value</FONT><FONT size=2>;</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetFilterParts();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ApplyFilter();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp; else</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>if</FONT><FONT size=2> (</FONT><FONT color=#2b91af size=2>Regex</FONT><FONT size=2>.Matches(</FONT><FONT color=#0000ff size=2>value</FONT><FONT size=2>, </FONT></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#a31515 size=2>"[?[\\w ]+]? ?[=] ?'?[\\w|/: ]+'?"</FONT><FONT size=2>,</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RegexOptions</FONT><FONT size=2>.Singleline).Count &gt; 1)</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ArgumentException</FONT><FONT size=2>(</FONT><FONT color=#a31515 size=2>"Multi-column" +</FONT></P>
<P><FONT color=#a31515 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "filtering is </FONT><FONT color=#a31515><FONT size=2>not implemented."</FONT></FONT><FONT size=2>);</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;else</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>throw</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ArgumentException</FONT><FONT size=2>(</FONT><FONT color=#a31515 size=2>"Filter is not" </FONT><FONT size=2>+</P>
<P></FONT><FONT color=#a31515 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "in the format: propName = 'value'."</FONT><FONT size=2>);</P>
<P>RaiseListChangedEvents = </FONT><FONT color=#0000ff size=2>true</FONT><FONT size=2>;</P>
<P>OnListChanged(</FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ListChangedEventArgs</FONT><FONT size=2>(</FONT><FONT color=#2b91af size=2>ListChangedType</FONT><FONT size=2>.Reset, -1));</FONT></P>
<P><FONT size=2>}</FONT></P></BLOCKQUOTE>
<P><FONT size=2>}</P></BLOCKQUOTE>
<P></FONT></FONT><FONT size=2>}&nbsp;&nbsp;&nbsp; </P>
<P></FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> FilteredListView_ListChanged(</FONT><FONT color=#0000ff size=2>object</FONT><FONT size=2> sender, </FONT><FONT color=#2b91af size=2>ListChangedEventArgs</FONT><FONT size=2> e)</P>
<P>{</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp; MessageBox</FONT><FONT size=2>.Show(RaiseListChangedEvents.ToString());</P>
<P></FONT><FONT color=#008000 size=2>&nbsp;&nbsp; // Add the new item</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; if</FONT><FONT size=2> (e.ListChangedType == </FONT><FONT color=#2b91af size=2>ListChangedType</FONT><FONT size=2>.ItemAdded)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unfilteredListValue.Add(</FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>[e.NewIndex]);</P>
<P></FONT><FONT color=#008000 size=2>&nbsp; // Remove the new item</P></FONT><FONT size=2>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; if</FONT><FONT size=2> (e.ListChangedType == </FONT><FONT color=#2b91af size=2>ListChangedType</FONT><FONT size=2>.ItemDeleted)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp; unfilteredListValue.RemoveAt(e.NewIndex);</P>
<P>}</P>
<P mce_keep="true">&nbsp;</P>
<P></FONT><FONT color=#0000ff size=2>private</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> ApplyFilter()</P>
<P>{</P>
<P>&nbsp;&nbsp;&nbsp; unfilteredListValue.Clear();</P>
<P>&nbsp;&nbsp;&nbsp; unfilteredListValue.AddRange(</FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>.Items);</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; List</FONT><FONT size=2>&lt;T&gt; results = </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>List</FONT><FONT size=2>&lt;T&gt;();</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; PropertyDescriptor</FONT><FONT size=2> propDesc = </FONT><FONT color=#2b91af size=2>TypeDescriptor</FONT><FONT size=2>.GetProperties(</FONT><FONT color=#0000ff size=2>typeof</FONT><FONT size=2>(T))[FilterPropertyName];</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (propDesc != </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>)</P>
<P>&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int</FONT><FONT size=2> tempResults = -1;</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tempResults = FindCore(tempResults + 1, propDesc, FilterCompare);</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (tempResults != -1)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; results.Add(</FONT><FONT color=#0000ff size=2>this</FONT><FONT size=2>[tempResults]);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </FONT><FONT color=#0000ff size=2>while</FONT><FONT size=2> (tempResults != -1);</P>
<P>&nbsp;&nbsp;&nbsp; }</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; this</FONT><FONT size=2>.ClearItems();</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp; if</FONT><FONT size=2> (results != </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2> &amp;&amp; results.Count &gt; 0)</P>
<P>&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach</FONT><FONT size=2> (T itemFound </FONT><FONT color=#0000ff size=2>in</FONT><FONT size=2> results)</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this</FONT><FONT size=2>.Add(itemFound);</P>
<P>&nbsp;&nbsp; }</P>
<P>}</P>
<P mce_keep="true">&nbsp;</P>
<P></FONT><FONT color=#0000ff size=2>public</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>void</FONT><FONT size=2> GetFilterParts()</P>
<P>{</P>
<P mce_keep="true"></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; string</FONT><FONT size=2>[] filterParts = Filter.Split(</FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>char</FONT><FONT size=2>[] { </FONT><FONT color=#a31515 size=2>'='</FONT><FONT size=2> }, </FONT><FONT color=#2b91af size=2>StringSplitOptions</FONT><FONT size=2>.RemoveEmptyEntries);</P>
<P>&nbsp;&nbsp;&nbsp; filterPropertyNameValue = filterParts[0].Replace(</FONT><FONT color=#a31515 size=2>"["</FONT><FONT size=2>, </FONT><FONT color=#a31515 size=2>""</FONT><FONT size=2>).Replace(</FONT><FONT color=#a31515 size=2>"]"</FONT><FONT size=2>, </FONT><FONT color=#a31515 size=2>""</FONT><FONT size=2>).Trim(); </P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; PropertyDescriptor</FONT><FONT size=2> propDesc =</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp; TypeDescriptor</FONT><FONT size=2>.GetProperties(</FONT><FONT color=#0000ff size=2>typeof</FONT><FONT size=2>(T))[filterPropertyNameValue.ToString()];</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; if</FONT><FONT size=2> (propDesc != </FONT><FONT color=#0000ff size=2>null</FONT><FONT size=2>)</P>
<P>&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try</P></FONT><FONT size=2>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#2b91af size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TypeConverter</FONT><FONT size=2> converter = </FONT><FONT color=#2b91af size=2>TypeDescriptor</FONT><FONT size=2>.GetConverter(propDesc.PropertyType);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filterCompareValue = converter.ConvertFromString(filterParts[1].Replace(</FONT><FONT color=#a31515 size=2>"'"</FONT><FONT size=2>, </FONT><FONT color=#a31515 size=2>""</FONT><FONT size=2>).Trim());</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch</FONT><FONT size=2> (</FONT><FONT color=#2b91af size=2>NotSupportedException</FONT><FONT size=2>)</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ArgumentException</FONT><FONT size=2>(</FONT><FONT color=#a31515 size=2>"Specified filter value "</FONT><FONT size=2> +</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterCompare + </FONT><FONT color=#a31515 size=2>" can not be converted from string."</FONT><FONT size=2> +</P>
<P></FONT><FONT color=#a31515 size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "..Implement a type converter for "</FONT><FONT size=2> + propDesc.PropertyType.ToString());</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>}</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp; else</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>throw</FONT><FONT size=2> </FONT><FONT color=#0000ff size=2>new</FONT><FONT size=2> </FONT><FONT color=#2b91af size=2>ArgumentException</FONT><FONT size=2>(</FONT><FONT color=#a31515 size=2>"Specified property '"</FONT><FONT size=2> +</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterPropertyName + </FONT><FONT color=#a31515 size=2>"' is not found on type "</FONT><FONT size=2> +</P>
<P></FONT><FONT color=#0000ff size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typeof</FONT><FONT size=2>(T).Name + </FONT><FONT color=#a31515 size=2>"."</FONT><FONT size=2>);</P>
<P>&nbsp;&nbsp;&nbsp; }</P></FONT><FONT color=#0000ff size=2>
<P>#endregion</FONT><FONT size=2> Filtering</P></BLOCKQUOTE>
<P>}</P></FONT></FONT>]]></content:encoded>
    </item>
    <item>
      <title>DataGridviewAutoFilter sample updated</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/datagridviewautofilter-sample-updated</link>
      <pubDate>Wed, 05 Dec 2007 17:49:00 GMT</pubDate>
      <dc:creator><![CDATA[Karl Erickson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2007/12/05/datagridviewautofilter-sample-updated/</guid>
      <description><![CDATA[I've made a few bug-fixes to my DataGridViewAutoFilter sample, which is described in Building a...]]></description>
      <content:encoded><![CDATA[<P>I've made a few bug-fixes to my <STRONG>DataGridViewAutoFilter</STRONG> sample, which is described in <A class="" href="https://msdn2.microsoft.com/en-us/library/aa480727.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/aa480727.aspx">Building a Drop-Down Filter List for a DataGridView Column Header Cell</A>. It might be a week or two until the article is updated (as of December 5, 2007), but the new <A class="" href="https://www.microsoft.com/downloads/details.aspx?FamilyID=bea5c31b-e07a-46b5-8662-ecd798c0134d&amp;displaylang=en" mce_href="https://www.microsoft.com/downloads/details.aspx?FamilyID=bea5c31b-e07a-46b5-8662-ecd798c0134d&amp;displaylang=en">sample download</A> has already been posted. The download contains C# and VB projects, plus the updated article in Word 2003 format.</P>
<P>Here's a summary of the fixes:</P>
<UL>
<LI>The code that populates the drop-down list now does a case-insensitive match between the column's <STRONG>DataPropertyName</STRONG> and the data source properties. This is necessary because data-source property-access APIs are case-sensitive but <STRONG>DataPropertyName</STRONG> is case-insensitive. This caused problems with columns that are manually bound using a different casing than is used in the data source.</LI>
<LI>The code that populates the drop-down now does a null-value check before resetting the filter. The previous version caused some issues when binding to an <STRONG>lBindingListView </STRONG>implementation that my colleague Cheryl is working on for a forthcoming whitepaper.</LI>
<LI>The drop-down button size is now constrained by the header cell width as well as the height. Previously, the drop-down button for a very narrow column would overlap the adjacent column.</LI>
<LI>The drop-down button painting code is no longer executed if the button is of zero size. Previously, this caused an exception, for example when using the mouse to reduce the height of the column headers row to zero.</LI></UL>]]></content:encoded>
    </item>
    <item>
      <title>Client Application Services sample updated for Visual Studio 2008 RTM</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/client-application-services-sample-updated-for-visual-studio-2008-rtm</link>
      <pubDate>Tue, 04 Dec 2007 18:47:00 GMT</pubDate>
      <dc:creator><![CDATA[Karl Erickson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2007/12/04/client-application-services-sample-updated-for-visual-studio-2008-rtm/</guid>
      <description><![CDATA[I have updated my Client Application Services sample (previous posts here and here) to work with the...]]></description>
      <content:encoded><![CDATA[<P mce_keep="true">I have updated my Client Application Services sample (previous posts <A class="" href="https://blogs.msdn.com/winformsue/archive/2007/05/20/client-application-services-in-windows-forms-end-to-end-walkthrough-available.aspx" mce_href="https://blogs.msdn.com/winformsue/archive/2007/05/20/client-application-services-in-windows-forms-end-to-end-walkthrough-available.aspx">here</A> and <A class="" href="https://blogs.msdn.com/winformsue/archive/2007/09/27/client-application-services-sample-and-walkthrough-updated.aspx" mce_href="https://blogs.msdn.com/winformsue/archive/2007/09/27/client-application-services-sample-and-walkthrough-updated.aspx">here</A>) to work with the Visual Studio 2008 RTM release. See <A class="" href="https://blogs.msdn.com/winformsue/attachment/2752939.ashx" mce_href="https://blogs.msdn.com/winformsue/attachment/2752939.ashx">UsingClientApplicationServices.zip</A>. </P>
<P mce_keep="true">Additionally, the final documentation is now available on MSDN. See:</P>
<UL>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/bb384297(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bb384297(VS.90).aspx">Client Application Services</A></DIV></LI>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices(VS.90).aspx">System.Web.ClientServices</A></DIV></LI>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices.providers(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices.providers(VS.90).aspx">System.Web.ClientServices.Providers</A></DIV></LI></UL>
<P mce_keep="true">If you have used a previous version of the sample, you might need to deal with its remnants if you run into problems with this new version.&nbsp;Here are a few things you can try:</P>
<UL>
<LI>
<DIV mce_keep="true">If you get a CookieException when accessing the remote services, try clearing your IE cookie cache.</DIV></LI>
<LI>
<DIV mce_keep="true">If your application does not seem to be accessing the remote services, but everything looks properly configured, try deleting the application data folder. This folder location is indicated by the static <A class="" href="https://msdn2.microsoft.com/en-us/library/system.windows.forms.application.userappdatapath(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.windows.forms.application.userappdatapath(VS.90).aspx">Application.UserAppDataPath</A> property - the default location for Vista is C:\Users\&lt;username&gt;\AppData\Roaming\MSIT.</DIV></LI></UL>]]></content:encoded>
    </item>
    <item>
      <title>Client Application Services sample and walkthrough updated</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/client-application-services-sample-and-walkthrough-updated</link>
      <pubDate>Thu, 27 Sep 2007 15:26:00 GMT</pubDate>
      <dc:creator><![CDATA[Karl Erickson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2007/09/27/client-application-services-sample-and-walkthrough-updated/</guid>
      <description><![CDATA[Back in May, I posted an early version of my Client Application Services walkthrough, which was used...]]></description>
      <content:encoded><![CDATA[<P>Back in May, I <A class="" href="https://blogs.msdn.com/winformsue/archive/2007/05/20/client-application-services-in-windows-forms-end-to-end-walkthrough-available.aspx" mce_href="https://blogs.msdn.com/winformsue/archive/2007/05/20/client-application-services-in-windows-forms-end-to-end-walkthrough-available.aspx">posted</A> an early version of my Client Application Services walkthrough, which was used as a lab session at TechEd. Since then, there have been many improvements to both Visual Studio and the walkthrough. For one thing, the Beta 2 version of Orcas (now officially known as "Visual Studio 2008") was released. Unfortunately, this meant that the original Client Application Services sample became obsolete, since it won't run on Beta 2 without updating the project config files. </P>
<P>I have now replaced the original UsingClientApplicationServices.zip file, so if you'd like to preview the RTM version of this walkthrough and run the sample on the Beta 2 release, you can download the new <A class="" href="https://blogs.msdn.com/winformsue/attachment/2752939.ashx" mce_href="https://blogs.msdn.com/winformsue/attachment/2752939.ashx">UsingClientApplicationServices.zip</A>. Updates include:</P>
<UL>
<LI>A "remember me" feature for the login dialog box.</LI>
<LI>A logout button.</LI>
<LI>More robust code throughout, demonstrating extensive exception handling for fallback scenarios such as login expiration and server unavailability.</LI></UL>
<P>Enjoy!</P>
<P mce_keep="true"><STRONG>UPDATE (12/04/2007):</STRONG> <A class="" href="https://blogs.msdn.com/winformsue/attachment/2752939.ashx" mce_href="https://blogs.msdn.com/winformsue/attachment/2752939.ashx">UsingClientApplicationServices.zip</A> now includes VB and C# projects that will work with the Visual Studio 2008 RTM release. Additionally, the full documentation is now available on MSDN. See:</P>
<UL>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/bb384297(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bb384297(VS.90).aspx">Client Application Services</A></DIV></LI>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices(VS.90).aspx">System.Web.ClientServices</A></DIV></LI>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices.providers(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices.providers(VS.90).aspx">System.Web.ClientServices.Providers</A>&nbsp;</DIV></LI></UL>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>Tech-Ed Notes</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/tech-ed-notes</link>
      <pubDate>Mon, 11 Jun 2007 11:28:00 GMT</pubDate>
      <dc:creator><![CDATA[Cheryl Simmons]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2007/06/11/tech-ed-notes/</guid>
      <description><![CDATA[Thanks to everyone who stopped by the Acropolis and Windows Forms booth at Tech-Ed! Double thanks if...]]></description>
      <content:encoded><![CDATA[<P>Thanks to everyone who stopped by the Acropolis and Windows Forms booth at Tech-Ed! Double thanks if you answered a few of my questions about documentation. You can be sure that the Windows .NET Client UE team will be reading your comments. </P>
<P>A few of you reported your frustration with the Smart Client Orcas Features lab, as you were not able to cut and paste from the lab document to Visual Studio. In addition to viewing and downloading the lab from the Tech-Ed site, you can check&nbsp;it out right on this blog, as Karl posted the&nbsp;<A class="" title="Orcas features walkthrough" href="https://blogs.msdn.com/winformsue/archive/2007/05/20/client-application-services-in-windows-forms-end-to-end-walkthrough-available.aspx" mce_href="https://blogs.msdn.com/winformsue/archive/2007/05/20/client-application-services-in-windows-forms-end-to-end-walkthrough-available.aspx">walkthrough</A> a couple of weeks ago.</P>
<P>If you didn't have the chance to attend Tech-Ed,&nbsp;or did attend, but want to revisit your favorite parts, make sure and check out <A class="" href="https://virtualteched.com/" mce_href="https://virtualteched.com">Virtual Tech-Ed</A>.</P>]]></content:encoded>
    </item>
    <item>
      <title>Client Application Services in Windows Forms: End-to-End Walkthrough Available</title>
      <link>https://docs.microsoft.com/archive/blogs/winformsue/client-application-services-in-windows-forms-end-to-end-walkthrough-available</link>
      <pubDate>Sun, 20 May 2007 12:34:00 GMT</pubDate>
      <dc:creator><![CDATA[Karl Erickson]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/winformsue/2007/05/20/client-application-services-in-windows-forms-end-to-end-walkthrough-available/</guid>
      <description><![CDATA[The Beta 1 release of Visual Studio Code Name "Orcas" includes a new feature called Client...]]></description>
      <content:encoded><![CDATA[<P>The Beta 1 release of <A class="" href="https://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx" target=_blank mce_href="https://msdn2.microsoft.com/en-us/vstudio/aa700831.aspx">Visual Studio Code Name "Orcas"</A> includes a new feature called Client Application Services. This feature enables Windows client applications to easily access user-management services&nbsp;hosted by a centralized ASP.NET Web service application. </P>
<P>The documentation for client application services is still in progress, but we have created an end-to-end walkthrough&nbsp;to demonstrate the key features. This walkthrough will be used as a lab session at the upcoming TechEd 2007 conference, but if you want a sneak peek, download the attached zip file, which contains the walkthrough and sample projects in Visual Basic and C#. </P>
<P><EM>(From the walkthrough introduction:)</EM> In this walkthrough, you perform the following tasks:</P>
<UL>
<LI>Create a Windows Forms application and use the Visual Studio project designer to enable and configure client application services.&nbsp;</LI>
<LI>Create a simple ASP.NET Web Service application to host the application services and test your client configuration.</LI>
<LI>Add forms authentication to your application. You will start by using a hard-coded user name and password to test the service. You will then add a login form by specifying it as a credentials provider in your application configuration.&nbsp;</LI>
<LI>Add role-based functionality, enabling and displaying a button only for users in the "manager" role.&nbsp;</LI>
<LI>Access Web settings. You will start by loading Web settings for an authenticated (test) user on the Settings page of the project designer. You will then use the Windows Forms Designer to bind a text box to a Web setting. Finally, you will save the modified value back to the server.&nbsp;</LI>
<LI>Enable offline mode. You will provide a check box so that users can specify their connection status. You will then use this value to specify whether the client application service providers will use locally cached data instead of accessing their Web services. Finally, you will re-authenticate the current user when the application returns to online mode. </LI></UL>
<P mce_keep="true"><STRONG>UPDATE (9/27/2007):</STRONG> I have extensively revised and updated this walkthrough for the Visual Studio 2008 RTM documentation. To preview these updates, download the attached UsingClientApplicationServices.zip file, which includes the new walkthrough plus VB and C# projects containing updated Visual Studio solutions that work with the Visual Studio 2008 (formerly code-named "Orcas") Beta 2 release. These updates include a "remember me" login feature, a logout button, and more robust code that demonstrates appropriate exception handling for cases such as login expiration and server unavailability. Enjoy!</P>
<P mce_keep="true"><STRONG>UPDATE (12/04/2007):</STRONG> The attached UsingClientApplicationServices.zip now includes VB and C# projects that will work with the Visual Studio 2008 RTM release. Additionally, the full documentation is now available on MSDN. See:</P>
<UL>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/bb384297(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bb384297(VS.90).aspx">Client Application Services</A></DIV></LI>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices(VS.90).aspx">System.Web.ClientServices</A></DIV></LI>
<LI>
<DIV mce_keep="true"><A class="" href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices.providers(VS.90).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.web.clientservices.providers(VS.90).aspx">System.Web.ClientServices.Providers</A></DIV></LI></UL>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/02/75/29/39/UsingClientApplicationServices.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-02-75-29-39/UsingClientApplicationServices.zip">UsingClientApplicationServices.zip</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>