<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1555359752425089845</id><updated>2011-11-13T08:26:50.526-08:00</updated><category term='C#'/><category term='CruiseControl.NET'/><category term='Custom Control'/><category term='Intro'/><category term='MVC'/><category term='MVVM'/><category term='Surround'/><category term='Prism'/><category term='John Wayne'/><category term='Delphi'/><category term='CI'/><category term='WPF'/><category term='ListView'/><title type='text'>inpwtepydjuf</title><subtitle type='html'>Anubis who is before his mountain</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-8483573461528846890</id><published>2011-02-14T00:03:00.001-08:00</published><updated>2011-02-14T00:05:47.866-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Prism'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Prism 4.0 learnings</title><content type='html'>I have started to plan to use Prism 4.0 in one of my organisations internal applications. Previously I created a shell application and several modules that implement a standard interface. Having looked at Prism, much of this is already done via the templates that are available. &lt;br /&gt;&lt;br /&gt;I'll post some thoughts, problems and examples when I have something concrete.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-8483573461528846890?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/8483573461528846890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=8483573461528846890' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8483573461528846890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8483573461528846890'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2011/02/prism-40-learnings.html' title='Prism 4.0 learnings'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-8788914037334163657</id><published>2011-01-10T00:08:00.000-08:00</published><updated>2011-01-10T05:28:13.937-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='ListView'/><category scheme='http://www.blogger.com/atom/ns#' term='Custom Control'/><title type='text'>Extended ListView WPF Custom Control (Part 1)</title><content type='html'>I am trying to write a WPF control that can be used in my projects to provide a standardised look and feel for data that is presented via grids. I'll put my thoughts down here, as a aid to my fading memory.&lt;br /&gt;&lt;br /&gt;First I'll create the control, descended from ContentControl (as it will contain further content)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;namespace Controls&lt;br /&gt;{&lt;br /&gt;    using System;&lt;br /&gt;    using System.Windows.Controls;&lt;br /&gt;    using System.Windows;&lt;br /&gt;    using System.Windows.Input;&lt;br /&gt;    using System.ComponentModel;&lt;br /&gt;&lt;br /&gt;    public class ListViewExtended  : ContentControl&lt;br /&gt;    {&lt;br /&gt;        static ListViewExtended()&lt;br /&gt;        {&lt;br /&gt;            DefaultStyleKeyProperty.OverrideMetadata(typeof(ListViewExtended), &lt;br /&gt;                        new FrameworkPropertyMetadata(typeof(ListViewExtended)));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is really simple, and is a standard setup, next the difficult bit is creating the correct XAML template, this looks (in the initial version anyway), like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    &lt;Style TargetType="{x:Type local:ListViewExtended}"&gt;&lt;br /&gt;        &lt;Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/&gt;&lt;br /&gt;        &lt;Setter Property="Focusable" Value="False" /&gt;&lt;br /&gt;        &lt;Setter Property="Template"&gt;&lt;br /&gt;            &lt;/Setter.Value&gt;&lt;br /&gt;                &lt;/ControlTemplate TargetType="{x:Type local:ListViewExtended}"&gt;&lt;br /&gt;                    &lt;br /&gt;                   &lt;Border Background="{TemplateBinding Background}"&lt;br /&gt;                          BorderBrush="{TemplateBinding BorderBrush}"&lt;br /&gt;                          BorderThickness="{TemplateBinding BorderThickness}"&gt;&lt;br /&gt;                        &lt;ListView&gt;                          &lt;br /&gt;                          ItemContainerStyle="{StaticResource alternatingListViewItemStyle}"&lt;br /&gt;                          AlternationCount="2"&gt;&lt;br /&gt;                            &lt;ContentPresenter/&gt;&lt;br /&gt;                        &lt;/ListView&gt; &lt;br /&gt;                    &lt;/Border&gt;&gt;             &lt;br /&gt;            &lt;/ControlTemplate&gt;&lt;br /&gt;            &lt;/Setter.Value&gt;&lt;br /&gt;        &lt;/Setter&gt;        &lt;br /&gt;    &lt;/Style&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This can be used as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;        &lt;extToolkit:ListViewExtended&gt;&lt;br /&gt;            &lt;ListView&gt;&lt;br /&gt;                &lt;ListView.View&gt;&lt;br /&gt;                    &lt;GridView&gt;&lt;br /&gt;                        &lt;GridViewColumn Width="140" Header="Column 1" /&gt;&lt;br /&gt;                        &lt;GridViewColumn Width="140" Header="Column 2" /&gt;&lt;br /&gt;                        &lt;GridViewColumn Width="140" Header="Column 3" /&gt;&lt;br /&gt;                    &lt;/GridView&gt;&lt;br /&gt;                &lt;/ListView.View&gt;&lt;br /&gt;            &lt;/ListView&gt;&lt;br /&gt;        &lt;/extToolkit:ListViewExtended&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I'll tidy this up and add a screenshot later, and then extend the example to show it doing what I want it actually to do in the next post&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-8788914037334163657?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/8788914037334163657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=8788914037334163657' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8788914037334163657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8788914037334163657'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2011/01/extended-listview-wpf-custom-control.html' title='Extended ListView WPF Custom Control (Part 1)'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-3316229531701263611</id><published>2010-12-11T09:45:00.000-08:00</published><updated>2010-12-11T10:03:58.460-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVVM'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>MVVM RelayCommands and BackgroundWorker</title><content type='html'>This is largely cribbed from elsewhere, but I wanted to have a system where a &lt;span style="font-family:courier new;"&gt;RelayCommand&lt;/span&gt; starts off an asynchronous update of the &lt;span style="font-family:courier new;"&gt;Model&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;First we have to have a flag to hold the idle status&lt;br /&gt;&lt;pre&gt;public bool IsIdle ( get; set; }&lt;br /&gt;&lt;/pre&gt;The &lt;span style="font-family:courier new;"&gt;RelayCommand&lt;/span&gt; command needs to bind its &lt;span style="font-family:courier new;"&gt;CanExecute&lt;/span&gt; to this property&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;_getCommandData = new RelayCommand (&lt;br /&gt; () =&gt; GetTimeSheet(),&lt;br /&gt; () =&gt; IsIdle);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This means that the WPF item bound to this command (in this case a button), is disabled when the idle status is set to false.&lt;br /&gt;&lt;br /&gt;So in order to use this, and to not bung up the main UI thread, we need to run the command in a &lt;span style="font-family:courier new;"&gt;BackgroundWorker&lt;/span&gt; thread&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;protected void DoWork(Action work)&lt;br /&gt;{&lt;br /&gt; idle = false;&lt;br /&gt; var worker = new BackgroundWorker();&lt;br /&gt; worker.DoWork += (sender, e) =&gt; work();&lt;br /&gt; worker.RunWorkerCompleted += (sender, e) =&gt; Idle = true;&lt;br /&gt; worker.RunWorkerAsync();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void GetTimeSheet()&lt;br /&gt;{&lt;br /&gt; DoWork (delegate() {&lt;br /&gt;   _model.GetTimeSheet();&lt;br /&gt;   TimeSheetData = _model.TimeSheetData;&lt;br /&gt; });&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-3316229531701263611?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/3316229531701263611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=3316229531701263611' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/3316229531701263611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/3316229531701263611'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2010/12/mvvm-relaycommands-and-backgroundworker.html' title='MVVM RelayCommands and BackgroundWorker'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-8242030279218459954</id><published>2010-03-06T10:41:00.000-08:00</published><updated>2010-03-06T10:42:17.459-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><title type='text'>TLBs and Delphi</title><content type='html'>We register the capabilities of Delphi applications using TLB files. However, from reading &lt;a href="http://msdn.microsoft.com/en-us/library/aa372092%28VS.85%29.aspx" rel="nofollow"&gt;MSDN documentation&lt;/a&gt;, "Installation package authors are strongly advised against using the TypeLib table. Instead, they should register type libraries by using the Registry table". Does anyone have any advice on how to do this in a 'Delphi' way for Windows 7?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-8242030279218459954?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/8242030279218459954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=8242030279218459954' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8242030279218459954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8242030279218459954'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2010/03/tlbs-and-delphi.html' title='TLBs and Delphi'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-8496099348542042879</id><published>2010-02-27T13:37:00.000-08:00</published><updated>2010-02-27T14:02:52.204-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='CI'/><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Surround'/><title type='text'>Delphi/Surround/Cruisecontrol.net howto (updated)</title><content type='html'>This is a further draft of what I had to do to get CruiseControl.Net and Delphi to play nicely - I will fill out further the details later!&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Configured IIS in Windows (see &lt;a href="http://www.webwizguide.com/kb/asp_tutorials/installing_iis_winXP_pro.asp"&gt;here&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Install CruiseControl.Net 3.5 RC1 (see &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/CCNet+1.5+RC1+Release+Notes"&gt;release notes&lt;/a&gt;) - Make sure that the user that the CruiseControl.Net is being run by is able to see and use Delphi (i.e. probably not by default)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Install CCTray&lt;/li&gt;&lt;li&gt;Set the BDS environment setting to point to where Delphi lives (this may have been done when Delphi was installed)&lt;/li&gt;&lt;li&gt;Create a definitions.xml file that has all of the required defaults, for accessing Surround, MSBuild, etc.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create a project to test. It is difficult to post a real example, as this is code that my company owns, rather than me, but an example could be pulled out and added to this article.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Setup connection to Seapine Surround. I had a real problem with using Delphi and Surround, as by default the code is checked out as readonly, and Delphi needs to write to the working directory (especially when building typelibraries, etc). I have not spent too much time fiddling with it as I have a &lt;a href="http://jira.public.thoughtworks.org/browse/CCNET-1590"&gt;patch for the CruiseControl.NET source&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Setup the MSBuild section to build the application (in the definitions.xml file)&lt;/li&gt;&lt;li&gt;Setup the configuration to be managed by CruiseControl.NET and Surround, so that the files can be just checked out, modified and then checked in again - this avoids having to access the server machine.&lt;/li&gt;&lt;li&gt;Each developer now gets emailed whenever a build fails, and we can see the running of tests as well, after each build, see below.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Modify the DUnit tests to &lt;a href="http://delphixtreme.com/wordpress/?page_id=8"&gt;output XML&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;This I did using the code from the link above, and changed the base UnitTest program code to look like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var&lt;br /&gt;res : TTestResult;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;if IsConsole then&lt;br /&gt;  if ParamCount &lt;&gt; 0 then&lt;br /&gt;    if (copy(ParamStr(1), 0, 5) = '/xml=') then&lt;br /&gt;      res := XMLTestRunner.RunRegisteredTests(copy(ParamStr(1), 6, length(ParamStr(1)) -5))&lt;br /&gt;    else&lt;br /&gt;      res := TextTestRunner.RunRegisteredTests&lt;br /&gt;  else&lt;br /&gt;      res := TextTestRunner.RunRegisteredTests&lt;br /&gt;else&lt;br /&gt;  GUITestRunner.RunRegisteredTests;&lt;br /&gt;&lt;br /&gt;if (res.ErrorCount &lt;&gt; 0) then&lt;br /&gt;  halt (1);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Other things I have done ...&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Modify (legally I'm not sure if I can publish it) the code from &lt;a href="http://www.run-time-systems.com/ccp/"&gt;Run-Time Systems Cyclomatic Complexity Calculator for Delphi&lt;/a&gt; so that it outputs the results as an XML file - it actually does this already internally, but doesn't write the results out.&lt;/li&gt;&lt;li&gt;Create a task to generate developer documentation using doc-o-matic as a task.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-8496099348542042879?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/8496099348542042879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=8496099348542042879' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8496099348542042879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8496099348542042879'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2010/02/delphisurroundcruisecontrolnet-howto.html' title='Delphi/Surround/Cruisecontrol.net howto (updated)'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-7468682479678596387</id><published>2010-01-02T12:07:00.001-08:00</published><updated>2010-01-02T12:07:58.045-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><title type='text'>MVC Framework in Delphi</title><content type='html'>A real world example can be found here &lt;a href="http://www.carterconsulting.org.uk/MVP.htm"&gt;on Joanna Carter's&lt;/a&gt; pages.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-7468682479678596387?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/7468682479678596387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=7468682479678596387' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/7468682479678596387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/7468682479678596387'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2010/01/mvc-framework-in-delphi.html' title='MVC Framework in Delphi'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-457409454845775597</id><published>2009-09-06T14:26:00.000-07:00</published><updated>2009-09-07T13:25:56.339-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><title type='text'>ListViews</title><content type='html'>Things I can do with ListViews:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.scalabium.com/faq/dct0159.htm"&gt;Flat header Vs. 3D header&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.swissdelphicenter.ch/torry/showcode.php?id=1264"&gt;capture a column resize event in a TListView?&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.swissdelphicenter.ch/en/showcode.php?id=2133"&gt;Prevent resizing&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.codeproject.com/KB/list/HeaderRightClick.aspx"&gt;Handling Right-Click Events in ListView Column Headers&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-457409454845775597?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/457409454845775597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=457409454845775597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/457409454845775597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/457409454845775597'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/09/listviews.html' title='ListViews'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-5499132057083501970</id><published>2009-05-07T15:46:00.000-07:00</published><updated>2009-05-07T15:50:05.985-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><title type='text'>CI Updated</title><content type='html'>I now have all of our projects in CCNET, and am using this to control the port of code to Delphi 2009. I am also moving code around, so this helps. I had to patch a few things, but I have DUnit outputing xml that is then picked up by CCNET and displayed graphically (this is cool).&lt;br /&gt;&lt;br /&gt;I have also taken the Cyclometric Complexity tool that I use and created a command-line version (this used the OTA interface before), which also outputs to XML. I'll then plug this into the projects and this will allow us to automatically measure complexity!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-5499132057083501970?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/5499132057083501970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=5499132057083501970' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/5499132057083501970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/5499132057083501970'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/05/ci-updated.html' title='CI Updated'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-2918576564676313037</id><published>2009-04-16T13:35:00.000-07:00</published><updated>2009-04-16T13:37:02.029-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><title type='text'>Getting testing working</title><content type='html'>OK, so I have the source checked out, and then I have built it. I even have a test application, that outputs XML. However, we have a graphical login. So I need to be able to pass in the signon somehow. OK, so I need to think a bit more about this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-2918576564676313037?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/2918576564676313037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=2918576564676313037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/2918576564676313037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/2918576564676313037'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/04/getting-testing-working.html' title='Getting testing working'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-4397022321585422922</id><published>2009-04-07T00:08:00.000-07:00</published><updated>2009-04-07T00:37:31.305-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='CI'/><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><title type='text'>Cruisecontrol.net howto (draft)</title><content type='html'>This is a draft of what I had to do to get CruiseControl.Net and Delphi to play nicely - I will fill out the details later!&lt;br /&gt;&lt;br /&gt;1. Install Apache 2.&lt;br /&gt;2. Install &lt;a href="http://weblogs.asp.net/israelio/archive/2005/09/11/424852.aspx"&gt;Mod_ASPDotNet&lt;/a&gt;.&lt;br /&gt;3. Install CruiseControl.Net.&lt;br /&gt;4. Install CCTray.&lt;br /&gt;5. Create a project to test.&lt;br /&gt;7. Setup connection to Seapine Surround.&lt;br /&gt;8. Setup the MSBuild section to build the application.&lt;br /&gt;9. Modify the DUnit tests to &lt;a href="http://delphixtreme.com/wordpress/?page_id=8"&gt;output XML&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This I did using the entry above, and changed the base UnitTest program code to look like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var&lt;br /&gt;  res : TTestResult;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;  if IsConsole then&lt;br /&gt;    if ParamCount &lt;&gt; 0 then&lt;br /&gt;      if (copy(ParamStr(1), 0, 5) = '/xml=') then&lt;br /&gt;        res := XMLTestRunner.RunRegisteredTests(copy(ParamStr(1), 6, length(ParamStr(1)) -5))&lt;br /&gt;      else&lt;br /&gt;        res := TextTestRunner.RunRegisteredTests&lt;br /&gt;    else&lt;br /&gt;        res := TextTestRunner.RunRegisteredTests&lt;br /&gt;  else&lt;br /&gt;    GUITestRunner.RunRegisteredTests;&lt;br /&gt;&lt;br /&gt;  if (res.ErrorCount &lt;&gt; 0) then&lt;br /&gt;    halt (1);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;More later!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-4397022321585422922?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/4397022321585422922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=4397022321585422922' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/4397022321585422922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/4397022321585422922'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/04/cruisecontrolnet-howto-draft.html' title='Cruisecontrol.net howto (draft)'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-4441823896239593016</id><published>2009-04-06T08:02:00.000-07:00</published><updated>2009-04-06T08:05:59.149-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='CI'/><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><title type='text'>CI Update</title><content type='html'>Well, after much messing about I now have CI working for Delphi. It checks out the code from Surround (easy to configure), calls MSBuild (again easy), and this then compiles the Delphi source (tricky and required me to mess about and reinstall CruiseControl.NET). It now checks out 5 projects (3 of which compile, 1 fails due to a missed file, and 1 needs an project to be registered), which is about what I expected. &lt;br /&gt;&lt;br /&gt;Hurrah!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-4441823896239593016?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/4441823896239593016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=4441823896239593016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/4441823896239593016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/4441823896239593016'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/04/ci-update.html' title='CI Update'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-2663168414834296852</id><published>2009-04-04T16:25:00.000-07:00</published><updated>2009-04-16T08:42:52.264-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><title type='text'>Cruisecontrol.net update</title><content type='html'>Well, I have CCNet working and trying to build (but failing) Delphi 2009 code, using MSBuild, good news I found out what was wrong, the bad news was I had to hack the CC.NET source to get this to work.&lt;br /&gt;&lt;br /&gt;The cause of the problems was that Delphi 2009 uses the brcc32.exe to build its resources, which is obviously fine, but when the code is downloaded from Surround, it is read-only, so it create lots of .tmp files, all of which are read-only and so can't be written to. I downloaded the CC.NET source and changed the command line that is passed to Surround to checkout the code as read-write, and now the code compilation gets passed this.&lt;br /&gt;&lt;br /&gt;However, I am now stuck with MSBuild working from the command line, but not when run from CC.NET. Ho hum, I'm sure I can figure this out as well. Nothing is ever easy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-2663168414834296852?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/2663168414834296852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=2663168414834296852' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/2663168414834296852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/2663168414834296852'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/04/cruisecontrolnet-update.html' title='Cruisecontrol.net update'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-8287056230111159023</id><published>2009-04-01T06:32:00.000-07:00</published><updated>2009-04-16T08:43:17.011-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='CI'/><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><title type='text'>CI with Delphi</title><content type='html'>I am trying to get CruiseControl.NET to connect to a Surround SCM system and then check out and build (and then test if possible) projects.&lt;br /&gt;&lt;br /&gt;It was simple to install, but it needs as ASP.NET server to work (or so it seems). I've installed Apache and the mod_asp (or whatever it is called), and have got a simple ASP script to work, but can't get the CC.NET dashboard application to run.&lt;br /&gt;&lt;br /&gt;More news as it breaks.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update 1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I now have access to the CC.NET dashboard working. I can't get the command line that CC.NET builds to be correct, the settings seem OK, but I get the following ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Process command: E:\Program Files\Seapine\Surround SCM\sscm.exe cc * -d20090401153253:20090401153326 -r -bXXXX -p"XXXXXX" -x- -zABCABCDABCDEF:4900 -y"XXX:XXX"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Update 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Fixed the file locations, and started up the VPN, and now CruiseControl downloads the latest source, and tries to rebuild - the MSBuild process now gives the following error:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;E:\Documents\Mark\CCBuildDir\SSCMClone\D2009\XXXX\XXXX\XXXXX.dproj (,): &lt;br /&gt;&lt;br /&gt;errorMSB4057: The target "Rebuild" does not exist in the project.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So we are getting much closer, and this might be working before I go back to work&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-8287056230111159023?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/8287056230111159023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=8287056230111159023' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8287056230111159023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8287056230111159023'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/04/ci-with-delphi.html' title='CI with Delphi'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-8409269535996112467</id><published>2009-04-01T02:56:00.000-07:00</published><updated>2009-04-16T08:43:36.680-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CI'/><title type='text'>Continuous Integration and Delphi</title><content type='html'>&lt;h3 class="post-title"&gt;&lt;span style="font-size:100%;"&gt;&lt;a style="font-weight: normal;" href="http://projectvalley.com/weblog/2007/04/continuous-integration-with.html"&gt;Continuous Integration and Delphi using CruiseControl&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/h3&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-8409269535996112467?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/8409269535996112467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=8409269535996112467' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8409269535996112467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8409269535996112467'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/04/continuous-integration-and-delphi.html' title='Continuous Integration and Delphi'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-5749848027986359457</id><published>2009-01-11T02:38:00.000-08:00</published><updated>2009-01-11T02:42:33.743-08:00</updated><title type='text'>Actually implemented</title><content type='html'>I have started to build a proof of concept that actually implments code that does stuff, so can't actually post that code here, but basically it follows the same structures, with a command being sent via the Controller, and then being run across the model (and hence the data). The notification of errors is done by the &lt;code&gt;Notify&lt;/code&gt; mechanism, with whatever view knowing what to do with the errors statuses returned for each possible input.&lt;br /&gt;&lt;br /&gt;Once a change to client, stock, buy/sell, etc has been entered, then at the the moment the &lt;code&gt;Notify&lt;/code&gt; mechanism is directly fired, but what should happen is that the whole order should be validated at this point, allowing for cascadimg errors to be flagged.&lt;br /&gt;&lt;br /&gt;We will see on monday!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-5749848027986359457?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/5749848027986359457/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=5749848027986359457' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/5749848027986359457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/5749848027986359457'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/01/actually-implemented.html' title='Actually implemented'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-3972018760876671742</id><published>2009-01-06T07:35:00.000-08:00</published><updated>2009-01-06T07:41:42.891-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><title type='text'>MVC updated</title><content type='html'>I have had a small rest over Christmas and have decided that the code below needs to be refactored. I broke down all of the interfaces and implementations of them into different units, and begun to separate out the stuff that is MVC and stuff which used by the model.&lt;br /&gt;&lt;br /&gt;Specifically I broke down the command stuff and implemented descendants of TCommand that know what to do to the model - i.e. the model doesn't do anything other than respond to the data changes (or not as is the current state).&lt;br /&gt;&lt;br /&gt;This means I have ended up with code like this ..&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  TCalculateCommand = class (TCommand)&lt;br /&gt;    procedure Run (model : tObject); override;&lt;br /&gt;  end;&lt;br /&gt;  ..&lt;br /&gt;&lt;br /&gt;  { TCalculateCommand }&lt;br /&gt;&lt;br /&gt;  procedure TCalculateCommand.Run (model : tObject);&lt;br /&gt;  begin&lt;br /&gt;    (model as TDomainModel).Data.Price := self.Params[0].Value;&lt;br /&gt;    (model as TDomainModel).Data.Consideration := ((model as TDomainModel).Data.Size *&lt;br /&gt;          (model as TDomainModel).Data.Price) + (model as TDomainModel).Data.Charges;&lt;br /&gt;  end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This is a lot simpler in my view.&lt;br /&gt;&lt;br /&gt;However it doesn't solve the problem with how to indicate that a field is invalid?&lt;br /&gt;&lt;br /&gt;I might have to register each control with the model, so it knows which fields map to each control. That sounds like a lot to faff, but I don't know how else to do it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-3972018760876671742?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/3972018760876671742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=3972018760876671742' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/3972018760876671742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/3972018760876671742'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2009/01/mvc-updated.html' title='MVC updated'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-1189896838941291760</id><published>2008-11-07T15:02:00.000-08:00</published><updated>2008-11-07T15:04:39.866-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><title type='text'>MVC Update</title><content type='html'>In the real world, which I obviously can't post here, I have a problem where the result of the validation request does three things;&lt;br /&gt;&lt;br /&gt;1) Validates the input values&lt;br /&gt;2) Returns other information based on the inputs (i.e. Other client, stock details)&lt;br /&gt;3) Set whether a specific field input is valid or not.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-1189896838941291760?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/1189896838941291760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=1189896838941291760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1189896838941291760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1189896838941291760'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2008/11/mvc-update.html' title='MVC Update'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-1883032950342044389</id><published>2008-11-02T04:24:00.000-08:00</published><updated>2008-11-02T04:27:44.745-08:00</updated><title type='text'>More MVC!</title><content type='html'>A client search from would look like this ..&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;type&lt;br /&gt;  TForm3 = class(TForm, IObserver)&lt;br /&gt;    Button1: TButton;&lt;br /&gt;    Edit1: TEdit;&lt;br /&gt;    ListBox1: TListBox;&lt;br /&gt;    Button2: TButton;&lt;br /&gt;    Button3: TButton;&lt;br /&gt;    procedure FormCreate(Sender: TObject);&lt;br /&gt;    procedure Button1Click(Sender: TObject);&lt;br /&gt;    procedure Button3Click(Sender: TObject);&lt;br /&gt;    procedure Button2Click(Sender: TObject);&lt;br /&gt;  private&lt;br /&gt;    { Private declarations }&lt;br /&gt;  public&lt;br /&gt;    { Public declarations }&lt;br /&gt;    procedure UpdateView (obj : TObject);&lt;br /&gt;  end;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;procedure TForm3.Button1Click(Sender: TObject);&lt;br /&gt;var&lt;br /&gt;  c : TCommand;&lt;br /&gt;  o : TCommandParam;&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;  c := TCommand.Create ('SEARCH');&lt;br /&gt;&lt;br /&gt;  o := TCommandParam.Create;&lt;br /&gt;  o.Name := edit1.Text;&lt;br /&gt;&lt;br /&gt;  c.AddParam(o);&lt;br /&gt;&lt;br /&gt;  Controller.DoCommand(c);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TForm3.Button2Click(Sender: TObject);&lt;br /&gt;begin&lt;br /&gt;  ModalResult := mrOK;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TForm3.Button3Click(Sender: TObject);&lt;br /&gt;begin&lt;br /&gt;  ModalResult := mrCancel;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TForm3.FormCreate(Sender: TObject);&lt;br /&gt;begin&lt;br /&gt;  Controller.AddView (self);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TForm3.UpdateView (obj : TObject);&lt;br /&gt;var&lt;br /&gt;  val : String;&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;  // Update the view here&lt;br /&gt;  if ((obj as TDomainModel).ClientSearchResult &lt;&gt; nil) then&lt;br /&gt;  begin&lt;br /&gt;    for val in (obj as TDomainModel).ClientSearchResult do&lt;br /&gt;    begin&lt;br /&gt;      ListBox1.AddItem(val, nil);&lt;br /&gt;    end;&lt;br /&gt;  end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I have merge the View classes with the actual form, in order to make the code relationships a little clearer.&lt;br /&gt;&lt;br /&gt;I'm really happy with all of the, and I think it will be applicable for the requirements I have at work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-1883032950342044389?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/1883032950342044389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=1883032950342044389' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1883032950342044389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1883032950342044389'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2008/11/more-mvc.html' title='More MVC!'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-1974238848705421164</id><published>2008-10-31T17:55:00.000-07:00</published><updated>2008-11-02T04:24:08.331-08:00</updated><title type='text'>MVC questions</title><content type='html'>Having done all of the below, I am still left with a list of questions&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Should I be using threads to do this ?&lt;/li&gt;&lt;li&gt;When the command requires interaction (i.e. if I want a form to search of a client or a stock item), should it be owned by the Model, Controller or View ?&lt;/li&gt;&lt;/ol&gt;To answer 2., the view owns the form, and and is updated by the model in the same way as before.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-1974238848705421164?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/1974238848705421164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=1974238848705421164' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1974238848705421164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1974238848705421164'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2008/10/mvc-questions.html' title='MVC questions'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-7568945003140979485</id><published>2008-10-31T17:40:00.000-07:00</published><updated>2008-10-31T17:55:16.997-07:00</updated><title type='text'>MVC in Delphi (Part III)</title><content type='html'>As an experiment I have changed the DomainModel of my example, to be a more complex object, encapsulating an 'order'. This can be updated, calculated and reset with out the View and the Controller having to change.&lt;br /&gt;&lt;br /&gt;The DomainModel now looks like this ..&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; TDomainObject = class&lt;br /&gt; private&lt;br /&gt;   FClient : String;&lt;br /&gt;   FStock : String;&lt;br /&gt;   FBuySell : String;&lt;br /&gt;   FSize : extended;&lt;br /&gt;   FPrice : extended;&lt;br /&gt;   FDate : String;&lt;br /&gt;&lt;br /&gt;   FConsideration : extended;&lt;br /&gt; public&lt;br /&gt;   property Client : String read FCLient write FClient;&lt;br /&gt;   property Stock : String read FStock write FStock;&lt;br /&gt;   property BuySell : String read FBuySell write FBuySell;&lt;br /&gt;   property Size : extended read FSize write FSize;&lt;br /&gt;   property Price : extended read FPrice write FPrice;&lt;br /&gt;   property Date : String read FDate write FDate;&lt;br /&gt;   property Consideration : extended read FConsideration write FConsideration;&lt;br /&gt; end;&lt;br /&gt;&lt;br /&gt; ///&lt;summary&gt;A small implementation of the MVC architecture&lt;/summary&gt;&lt;br /&gt; TDomainModel = class (TObservable)&lt;br /&gt; private&lt;br /&gt;   /// &lt;summary&gt;Underlying data object&lt;/summary&gt;&lt;br /&gt;   FData : TDomainObject;&lt;br /&gt;&lt;br /&gt; public&lt;br /&gt;   ///&lt;summary&gt;Property that represents the underlying data&lt;/summary&gt;&lt;br /&gt;   property Data : TDomainObject read FData write FData;&lt;br /&gt;&lt;br /&gt;   ///&lt;summary&gt;Executes the given command&lt;/summary&gt;&lt;br /&gt;   procedure DoCommand (cmd : TCommand); override;&lt;br /&gt;&lt;br /&gt;   ///&lt;summary&gt;Creates the underlying data&lt;/summary&gt;&lt;br /&gt;   constructor Create;&lt;br /&gt;&lt;br /&gt;   ///&lt;summary&gt;Function that is passed to the CommandThread for execution&lt;/summary&gt;&lt;br /&gt;   ///&lt;seealso cref="T:Command.CommandThread"&gt;TCommandThread&lt;/seealso&gt;&lt;br /&gt;   procedure ExecuteCommand (cmd : TCommand);&lt;br /&gt;&lt;br /&gt;   function ToString : String;&lt;br /&gt; end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In order to do this, some of the plumbing code had to change, but basically just to get the values in the views. I have define 3 views, 2 of which are associated with one form, and a more complex one that is associated with another form, as below;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; TFormView = class (TInterfacedObject, IObserver)&lt;br /&gt; private&lt;br /&gt;   Ffrm : TForm2;&lt;br /&gt; public&lt;br /&gt;   { Public declarations }&lt;br /&gt;   procedure UpdateView (obj : TObject);&lt;br /&gt;   constructor Create (frm : TForm2);&lt;br /&gt; end;&lt;br /&gt;&lt;br /&gt; TListView = class (TInterfacedObject, IObserver)&lt;br /&gt; private&lt;br /&gt;   Fctrl : TListBox;&lt;br /&gt; public&lt;br /&gt;   { Public declarations }&lt;br /&gt;   procedure UpdateView (obj : TObject);&lt;br /&gt;   constructor Create (ctrl : TListBox);&lt;br /&gt; end;&lt;br /&gt;&lt;br /&gt; TTextView = class (TInterfacedObject, IObserver)&lt;br /&gt; private&lt;br /&gt;   Fctrl : TStaticText;&lt;br /&gt; public&lt;br /&gt;   { Public declarations }&lt;br /&gt;   procedure UpdateView (obj : TObject);&lt;br /&gt;   constructor Create (ctrl : TStaticText);&lt;br /&gt; end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These are created and associated with the Model and Controller as follows;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;procedure TForm1.FormCreate(Sender: TObject);&lt;br /&gt;begin&lt;br /&gt; Controller.AddView (TListView.Create (ListBox1));&lt;br /&gt; Controller.AddView (TTextView.Create (StaticText1));&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;procedure TTextView.UpdateView (obj : TObject);&lt;br /&gt;begin&lt;br /&gt; Fctrl.Caption := FloatToStr((obj as TDomainModel).Data.Size);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TListView.UpdateView (obj : TObject);&lt;br /&gt;begin&lt;br /&gt; Fctrl.AddItem('Order = ' + (obj as TDomainModel).ToString, nil);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;procedure TForm2.FormCreate(Sender: TObject);&lt;br /&gt;begin&lt;br /&gt; Controller.AddView (TFormView.Create(Form2));&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;procedure TFormView.UpdateView (obj : TObject);&lt;br /&gt;begin&lt;br /&gt;// Fctrl.AddItem('Order = ' + (obj as TDomainModel).ToString, nil);&lt;br /&gt; Ffrm.lblStock.caption := (obj as TDomainModel).Data.Stock;&lt;br /&gt; Ffrm.lblClient.caption := (obj as TDomainModel).Data.Client;&lt;br /&gt; Ffrm.lblSize.caption := FloatToStr((obj as TDomainModel).Data.Size);&lt;br /&gt; Ffrm.lblPrice.caption := FloatToStr((obj as TDomainModel).Data.Price);&lt;br /&gt; Ffrm.lblValue.caption := FloatToStr((obj as TDomainModel).Data.Consideration);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This shows that a new view can be added, which out having to change anything in the Model or Controller.&lt;br /&gt;&lt;br /&gt;The first two Views are associated with the main form, and show a single value from the Model, and a list view representing the changes to the order. The third View is the state of the 'whole' order.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LBgVqqiGL_g/SQuoERDAZ_I/AAAAAAAAAA8/ATjaMBKPibk/s1600-h/Untitled2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 298px;" src="http://3.bp.blogspot.com/_LBgVqqiGL_g/SQuoERDAZ_I/AAAAAAAAAA8/ATjaMBKPibk/s320/Untitled2.jpg" alt="" id="BLOGGER_PHOTO_ID_5263485380761511922" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LBgVqqiGL_g/SQuoEvzbTYI/AAAAAAAAABE/isDN3jmJARQ/s1600-h/Untitled.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 208px; height: 200px;" src="http://3.bp.blogspot.com/_LBgVqqiGL_g/SQuoEvzbTYI/AAAAAAAAABE/isDN3jmJARQ/s320/Untitled.jpg" alt="" id="BLOGGER_PHOTO_ID_5263485389017664898" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-7568945003140979485?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/7568945003140979485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=7568945003140979485' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/7568945003140979485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/7568945003140979485'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2008/10/mvc-in-delphi-part-iii.html' title='MVC in Delphi (Part III)'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_LBgVqqiGL_g/SQuoERDAZ_I/AAAAAAAAAA8/ATjaMBKPibk/s72-c/Untitled2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-8191031808207677969</id><published>2008-10-28T10:25:00.000-07:00</published><updated>2008-10-28T10:26:22.996-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><title type='text'>MVC in Delphi (Part II)</title><content type='html'>The TCommand is clearly a &lt;a href="http://en.wikipedia.org/wiki/Command_pattern"&gt;Command&lt;/a&gt;, and should be slightly different, but I will sort that out later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-8191031808207677969?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/8191031808207677969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=8191031808207677969' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8191031808207677969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/8191031808207677969'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2008/10/mvc-in-delphi-part-ii.html' title='MVC in Delphi (Part II)'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-1636511965300149704</id><published>2008-10-28T02:50:00.000-07:00</published><updated>2009-04-17T03:41:33.116-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='John Wayne'/><title type='text'>John Wayne!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_LBgVqqiGL_g/SQbg6coQwHI/AAAAAAAAAAU/g5XWJ13GSA8/s1600-h/brannigan2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 148px;" src="http://2.bp.blogspot.com/_LBgVqqiGL_g/SQbg6coQwHI/AAAAAAAAAAU/g5XWJ13GSA8/s320/brannigan2.jpg" alt="" id="BLOGGER_PHOTO_ID_5262140509351100530" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The 1975 John Wayne film &lt;a href="http://en.wikipedia.org/wiki/Brannigan_%28film%29"&gt;Brannigan&lt;/a&gt; was filmed in London, more specifically there is a car chase that goes down the street I live in. Here is a still from the chase, showing people clearly standing around watching the action.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-1636511965300149704?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/1636511965300149704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=1636511965300149704' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1636511965300149704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1636511965300149704'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2008/10/john-wayne.html' title='John Wayne!'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_LBgVqqiGL_g/SQbg6coQwHI/AAAAAAAAAAU/g5XWJ13GSA8/s72-c/brannigan2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-1977704069150331493</id><published>2008-10-27T08:41:00.000-07:00</published><updated>2008-10-28T01:55:29.314-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><title type='text'>MVC in Delphi (Part I)</title><content type='html'>We have a large Delphi software project at work, that has been in development for the last 10 years and is now basically unmaintainable. It uses threads to create conversations with an iSeries I5 (an AS/400 in old money). These threads are unmanaged, interdependant and duplicated throughout the application.&lt;br /&gt;&lt;br /&gt;We have been on the point of refactoring many times, but have not had the time or the will-power to actually do it. So, here goes ...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;MVC&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Basically the &lt;a href="http://en.wikipedia.org/wiki/Model-view-controller"&gt;MVC&lt;/a&gt; pattern looks closest to what I need. A data domain, and dependant views on it, so it "... isolates &lt;a href="http://en.wikipedia.org/wiki/Business_logic" title="Business logic"&gt;business logic&lt;/a&gt; from &lt;a href="http://en.wikipedia.org/wiki/User_interface" title="User interface"&gt;user interface&lt;/a&gt; considerations..."&lt;br /&gt;&lt;br /&gt;The parts of the pattern are ..&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LBgVqqiGL_g/SQbM-VAKNtI/AAAAAAAAAAM/2dh506o6Ank/s1600-h/mvc.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 179px; height: 155px;" src="http://4.bp.blogspot.com/_LBgVqqiGL_g/SQbM-VAKNtI/AAAAAAAAAAM/2dh506o6Ank/s320/mvc.png" alt="" id="BLOGGER_PHOTO_ID_5262118585790772946" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Model&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is basically an Observable ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  IObservable = interface&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      procedure RegisterObserver (obs : IObserver);&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;      procedure UnregisterObserver (obs : IObserver);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      procedure Notify (const obj : TObject);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      procedure ClearObservers ();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      procedure DoCommand (cmd : TCommand);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  end;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A default implementation of IObservable is the TObservable class, from which more concrete implementations should descend.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  ///&lt;summary&gt;This is the default implementation of IObservable&lt;/summary&gt;&lt;br /&gt;  ///&lt;seealso cref="T:MVCObserver.IObservable"&gt;IObservable&lt;/seealso&gt;&lt;br /&gt;  TObservable = class (TInterfacedObject,&lt;br /&gt;                       IObservable)&lt;br /&gt;  private&lt;br /&gt;    FObservers : TClassList;&lt;br /&gt;    FCurrent : TObject;&lt;br /&gt;&lt;br /&gt;  public&lt;br /&gt;    constructor Create;&lt;br /&gt;    destructor Destroy; override;&lt;br /&gt;&lt;br /&gt;    procedure SetCurrent (obj: TObject);&lt;br /&gt;&lt;br /&gt;    procedure RegisterObserver (obs : IObserver);&lt;br /&gt;    procedure UnregisterObserver (obs : IObserver);&lt;br /&gt;    procedure ClearObservers ();&lt;br /&gt;    procedure Notify (const obj : TObject);&lt;br /&gt;&lt;br /&gt;    procedure DoCommand (cmd : TCommand); virtual;&lt;br /&gt;&lt;br /&gt;    property Current : TObject read FCurrent write FCurrent;&lt;br /&gt;&lt;br /&gt;  end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;View&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is basically an Observer ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  IObserver = interface&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      procedure UpdateView (obj : TObject);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  end;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;a href="http://en.wikipedia.org/wiki/Observer_pattern"&gt;IObserver and IObservable pattern&lt;/a&gt;  is a standard pattern from &lt;b&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/b&gt;. It is half way there, with the Observable registering all of the Observer objects that are interested in when it changes. However, there is not a way of interacting with the Observer, in order to make it carry out operations, this is where the&lt;span style="font-family: georgia;"&gt; Controller &lt;/span&gt;comes in.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Controller&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;The controller is used (in my code at least) register all of the Observers with the Observables, and to marshal commands from the View to the Model. My interface for a Controller looks like this;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  IController = interface&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    function GetModel : IObservable;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    procedure SetModel (const m : IObservable);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    function GetView (index: integer): IObserver;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    procedure SetView (index: integer; const v : IObserver);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    property Model : IObservable read GetModel write SetModel;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    property Views[index: integer]: IObserver read GetView write SetView;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    procedure DoCommand (cmd : TCommand);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    procedure AddView (v : IObserver);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;  end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: georgia;"&gt;This maintains a list of Views (accessed via the Views property), and the Model which they are interested in.  The commands are processed via the DoCommand method (this is a bit of a hack I think, and I can't quite think of a way to do this nicely!).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Concrete Example&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So the interfaces above describe the basic building blocks of an MVC interface. Lets try and build a concrete example to see how it works.&lt;br /&gt;&lt;br /&gt;My example model will be a single extended value, which will be initialised at startup by the Model, and then operations can be carried out on it by the View, via the Controller.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;First we define the concrete model ...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  ///&lt;summary&gt;A small implementation of the MVC architecture&lt;/summary&gt;&lt;br /&gt;  TDomainModel = class (TObservable)&lt;br /&gt;  private&lt;br /&gt;    /// &lt;summary&gt;Underlying data object&lt;/summary&gt;&lt;br /&gt;    FData : extended;&lt;br /&gt;&lt;br /&gt;  public&lt;br /&gt;    ///&lt;summary&gt;Property that represents the underlying data&lt;/summary&gt;&lt;br /&gt;    property Data : extended read FData write FData;&lt;br /&gt;&lt;br /&gt;    ///&lt;summary&gt;Executes the given command&lt;/summary&gt;&lt;br /&gt;    procedure DoCommand (cmd : TCommand); override;&lt;br /&gt;&lt;br /&gt;    ///&lt;summary&gt;Creates the underlying data&lt;/summary&gt;&lt;br /&gt;    constructor Create;&lt;br /&gt;&lt;br /&gt;    ///&lt;summary&gt;Function that is passed to the CommandThread for execution&lt;/summary&gt;&lt;br /&gt;    ///&lt;seealso cref="T:Command.CommandThread"&gt;TCommandThread&lt;/seealso&gt;&lt;br /&gt;    procedure ExecuteCommand (cmd : TCommand);&lt;br /&gt;  end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As can be seen, we descend from the base class &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="font-family: courier new;"&gt;&lt;span style="font-family: georgia;"&gt;TObservable, which implements all of the IObservable methods, and provides some basic functionality needed by all TObservable objects (see above).&lt;br /&gt;&lt;br /&gt;The DoCommand method wraps up the TCommand object (more of that later), and then spawns off a thread to actually do the processing. This hides all of the gubbins of getting data and processing it from the Controller and the View. In the real example this would get stuff from the i5 via the conversation. It would mean that this method of using threads could be changed to use a managed queue, or whatever, without changing the View or the Controller, as they don't need to know HOW the data is fetched, just that it is ready.&lt;br /&gt;&lt;br /&gt;In the example below, we just do some very simple maths &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;procedure TDomainModel.DoCommand (cmd : TCommand);&lt;br /&gt;var&lt;br /&gt;  T : TCommandThread;&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;  t := TCommandThread.Create(true);&lt;br /&gt;&lt;br /&gt;  t.Cmd := cmd;&lt;br /&gt;  t.ParamList := cmd.ParamList;&lt;br /&gt;  t.Operation := ExecuteCommand;&lt;br /&gt;&lt;br /&gt;  t.Resume;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TDomainModel.ExecuteCommand (cmd : TCommand);&lt;br /&gt;begin&lt;br /&gt;  if cmd.Command = 'HALF' then&lt;br /&gt;  begin&lt;br /&gt;    FData := FData / 2;&lt;br /&gt;  end;&lt;br /&gt;&lt;br /&gt;  if cmd.Command = 'MULTIPLY' then&lt;br /&gt;  begin&lt;br /&gt;    FData := FData * 2;&lt;br /&gt;  end;&lt;br /&gt;&lt;br /&gt;  if cmd.Command = 'SET' then&lt;br /&gt;  begin&lt;br /&gt;    assert (cmd.ParamCount &lt;&gt; -1, 'SET requires a parameter value');&lt;br /&gt;    FData := cmd.Params[0].Value;&lt;br /&gt;  end;&lt;br /&gt;&lt;br /&gt;  if cmd.Command = 'ADD' then&lt;br /&gt;  begin&lt;br /&gt;    assert (cmd.ParamCount &lt;&gt; -1, 'ADD requires a parameter value');&lt;br /&gt;    FData := FData + cmd.Params[0].Value;&lt;br /&gt;  end;&lt;br /&gt;&lt;br /&gt;  if cmd.Command = 'ZERO' then&lt;br /&gt;  begin&lt;br /&gt;    FData := 0.0;&lt;br /&gt;  end;&lt;br /&gt;&lt;br /&gt;  Notify(self);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;constructor TDomainModel.Create;&lt;br /&gt;begin&lt;br /&gt;  FData := 10.0;&lt;br /&gt;end;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I'll finish off this a bit later, and upload the source for the example&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-1977704069150331493?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/1977704069150331493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=1977704069150331493' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1977704069150331493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/1977704069150331493'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2008/10/mvc-in-delphi.html' title='MVC in Delphi (Part I)'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_LBgVqqiGL_g/SQbM-VAKNtI/AAAAAAAAAAM/2dh506o6Ank/s72-c/mvc.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1555359752425089845.post-4976536639649866007</id><published>2008-09-21T06:11:00.000-07:00</published><updated>2008-10-28T01:25:57.545-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Intro'/><title type='text'>Hi</title><content type='html'>In this blog I hope to write about my adventures in Delphi, C# and probably some random stuff about Egyptology and wikipedia.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1555359752425089845-4976536639649866007?l=inpwtepydjuf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inpwtepydjuf.blogspot.com/feeds/4976536639649866007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1555359752425089845&amp;postID=4976536639649866007' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/4976536639649866007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1555359752425089845/posts/default/4976536639649866007'/><link rel='alternate' type='text/html' href='http://inpwtepydjuf.blogspot.com/2008/09/hi.html' title='Hi'/><author><name>inpw</name><uri>http://www.blogger.com/profile/04177513603832760696</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
