CodeProject, Introduction

WPF : Binding to individual collection items (but not in a ItemsControl)

Well I had a great day yesterday, and quite a surprising one, I had an issue with an idea I was working on, so naturally I turned to Josh Smith.

And guess what I, yes me the mere mortal managed to teach Josh something about WPF…Ha Ha, check that.

So here is what I taught Josh…..(still cant believe I managed to teach Josh something 😉 )

I want to be able to bind multiple controls that are all stand alone controls to a collection. Sounds simple enough right.

Check this code behind

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Collections.ObjectModel;
   4:  using System.Linq;
   5:  using System.Text;
   6:  using System.Windows;
   7:  using System.Windows.Controls;
   8:  using System.Windows.Data;
   9:  using System.Windows.Documents;
  10:  using System.Windows.Input;
  11:  using System.Windows.Media;
  12:  using System.Windows.Media.Imaging;
  13:  using System.Windows.Navigation;
  14:  using System.Windows.Shapes;
  15:  
  16:  namespace WPF_test
  17:  {
  18:      public partial class Window1 : Window
  19:      {
  20:          public ObservableCollection<string>
  21:              MyValues { get; private set; }
  22:  
  23:          public Window1()
  24:          {
  25:              MyValues = new ObservableCollection<string>();
  26:              MyValues.Add("array");
  27:              MyValues.Add("element");
  28:              MyValues.Add("bindings");
  29:              //use the ObservableCollection<string> MyValues  as
  30:              //the DataContext for the Window
  31:              this.DataContext = MyValues;
  32:              InitializeComponent();
  33:          }
  34:  
  35:          private void Button_Click_0(
  36:              object sender, RoutedEventArgs e)
  37:          {
  38:              MyValues.Clear();
  39:              MyValues.Add("bindings");
  40:              MyValues.Add("element");
  41:              MyValues.Add("array");
  42:          }
  43:  
  44:          private void Button_Click_1(
  45:              object sender, RoutedEventArgs e)
  46:          {
  47:              MyValues.Clear();
  48:              MyValues.Add("element");
  49:              MyValues.Add("bindings");
  50:              MyValues.Add("array");
  51:          }
  52:  
  53:          private void Button_Click_2(
  54:              object sender, RoutedEventArgs e)
  55:          {
  56:              MyValues.Clear();
  57:              MyValues.Add("array");
  58:              MyValues.Add("bindings");
  59:              MyValues.Add("element");
  60:          }
  61:      }
  62:  }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }And here is the XAML code. This is where the individual elements are bound to the MyValues collection. Lets see

   1:  <Window x:Class="WPF_test.Window1"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      Title="Window1" Height="300" Width="300">
   5:  
   6:  
   7:      <Window.Resources>
   8:          <ContentPresenter x:Key="cont1" Content="{Binding Path=.[0], Mode=OneWay}"/>
   9:          <ContentPresenter x:Key="cont2" Content="{Binding Path=.[1], Mode=OneWay}"/>
  10:          <ContentPresenter x:Key="cont3" Content="{Binding Path=.[2], Mode=OneWay}"/>
  11:      </Window.Resources>
  12:  
  13:      <StackPanel Orientation="Vertical">
  14:          <Button Content="{DynamicResource cont1}" Click="Button_Click_0"/>
  15:          <Button Content="{DynamicResource cont2}" Click="Button_Click_1"/>
  16:          <Button Content="{DynamicResource cont3}" Click="Button_Click_2"/>
  17:      </StackPanel>
  18:  
  19:  
  20:  </Window>
And real guts of this post is the Content="{Binding Path=.[0], Mode=OneWay}" part, see how it uses the
. notation, which means current Binding, and the [0] indexer.
Neat huh. And here it is running

image


And here is a demo project : wpf_test.zip
Introduction

.NET 3.5 3D Elements

I have just published a new article at codeproject, about using some of the new 3D WPF elements within .NET 3.5.

Here is a link to the article.

The article covers the usage of the following elements:

  • ContainerUIElement3D
  • ModelUIElement3D
  • Viewport2DVisual3D

Due to the nature of 3D, the only way that I can do the article any justice is to show you a video. As such please click on the image below to see a video of what the article covers in action:

 

videoLink

Its basically a simple RSSfeed being read using XLINQ and each 3d sphere represents a blog entry which can be clicked on.

Have fun folks

Introduction

Code Snippets For WPF

Rudi Grobler has already blogged about these code snippets over at his blog http://dotnet.org.za/rudi/archive/2008/03/11/wpf-snippets.aspx but I just wanted to make sure that I didn’t loose these.

So I’m just creating another entry here at my own site, so that I never loose these wonderful snippets.

Dr WPF code snippets

image

DR WPFs code snippets

 

IdentityMine WPF code snippets

image

IdentityMine (Blendables people) code snippets

 

There now ill never loose them…hope they help some more of you, and thanks for that post Rudi.

Introduction

Cool Database Tool

For the last 2 months Jan/Feb 2008, I have won the C# article of the month at codeproject, and as such, I receive a lot of free software. Which I normally don’t ever look at. The reason for this is simple. I write articles to share with people, so these free bits of software really are not much use to me. As when I publish a new article the reader of the article will NOT have the same software installed as me, so will not be able to run my code in Visual Studio.

So because of this I rarely even look at the free software that comes my way.

However at work I do a lot of work with databases, it used to be all SQL Server 2005. But now its Oracle 10g. Though I still prefer SQL Server by miles.

So as I like SQL Server, I look out for cool things to help me out in my day to day work.

One of the products that was part of the codeproject prize fund for these 2 months, actually turned out to be worth looking at. As I have done loads of database stuff in the past, so have an appreciation for any tool that saves me time. I feel this is one such product.

The product is a database re-synchronization component. Notice that its not an application but a component, which means you can embed it straight into your application and use it by calling the UpdateDatabase() directly on the component.

The component is called "Database Restyle" by a company called Perpetuumsoft, and it integrates straight into a .NET project.

I think the best way to demonstrate this components, capabilities is to have a look at what it does. I am using a SQL Server 2005 installation with the standard Northwind database installed. Notice below that at the moment there are no Scalar-Valued Functions as part of the Northwind database.

image

Now jumping over to Visual Studio (I’m using VS2008), we can see that there is a actual component we can drag to a Winforms/Console/Web application.

image

Now in code behind, I can simple use the components update method, and my database will re-synchronize with any thing that has been altered on the current schema. Thats the model the application is using.

Again maybe an example is required here. I am using the example that came with the Database Restyle component installed samples.

   1:  /*****************************************************************************
   2:  
   3:      This source file is a part of Database Restyle
   4:      
   5:      Copyright (c) 2008 Perpetuum Software LLC. All rights reserved.
   6:      THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 
   7:      OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
   8:      LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   9:      FITNESS FOR A PARTICULAR PURPOSE.
  10:      
  11:      Copyright (c) 2008 Perpetuum Software LLC. All rights reserved.
  12:  
  13:  *****************************************************************************/
  14:  using System;
  15:  using System.Collections.Generic;
  16:  using System.ComponentModel;
  17:  using System.Data;
  18:  using System.Data.SqlClient;
  19:  using System.Data.Linq.Mapping;
  20:  using System.Drawing;
  21:  using System.Linq;
  22:  using System.Text;
  23:  using System.Windows.Forms;
  24:  using PerpetuumSoft.DataModel.MsSql.Synchronizers;
  25:  using PerpetuumSoft.DataModel.MsSql;
  26:  using PerpetuumSoft.DataModel.LinqToSql;
  27:   
  28:  namespace LinqToSql
  29:  {
  30:      public partial class MainForm : Form
  31:      {
  32:          public MainForm()
  33:          {
  34:              InitializeComponent();
  35:              dbBuilder.CreateFunctions = true;
  36:              dbBuilder.FunctionRequire += new 
  37:                  EventHandler<PerpetuumSoft.DataModel.FunctionRequareEventArgs>
  38:                  dbBuilder_FunctionRequire);
  39:          }
  40:   
  41:          private StringBuilder log;
  42:   
  43:          private LinqDatabaseBuilder dbBuilder = new LinqDatabaseBuilder();
  44:   
  45:          private void dbBuilder_FunctionRequire(object sender, 
  46:              PerpetuumSoft.DataModel.FunctionRequareEventArgs e)
  47:          {
  48:              if (e.SchemaName == "dbo" && e.FunctionName == "ProductsUnderThisUnitPrice")
  49:              {
  50:                  string text =
  51:                      @"CREATE FUNCTION [dbo].[ProductsUnderThisUnitPrice]()
  52:                      RETURNS int
  53:                      AS
  54:                      BEGIN
  55:                         DECLARE @retval int
  56:                         SELECT @retval = COUNT(*) FROM Territory
  57:                         RETURN @retval
  58:                      END;";
  59:                  ScalarFunction function = new 
  60:                      PerpetuumSoft.DataModel.MsSql.ScalarFunction(e.FunctionName, text);
  61:                  function.ReturnValueType = new DataType.Int();
  62:                  e.Function = function;
  63:              }
  64:              else
  65:              {
  66:                  throw new Exception(String.Format("Unknown function: [{0}].[{1}].", 
  67:                      e.SchemaName, e.FunctionName));
  68:              }
  69:          }
  70:   
  71:          private void exitButton_Click(object sender, EventArgs e)
  72:          {
  73:              this.Close();
  74:          }
  75:   
  76:          private void syncButton_Click(object sender, EventArgs e)
  77:          {
  78:              try
  79:              {
  80:                  log = new StringBuilder();
  81:   
  82:                  MetaModel model = new AttributeMappingSource().
  83:                      GetModel(typeof(DataClassesDataContext));
  84:                  Database sourceDB = dbBuilder.CreateDatabase(model);
  85:                  databaseSync.UpdateDatabase(sourceDB, GetConnectionString());
  86:   
  87:                  logTextBox.Text = log.ToString();
  88:              }
  89:              catch (Exception ex)
  90:              {
  91:                  logTextBox.Text = log.ToString();
  92:                  logTextBox.Text += ex.ToString();
  93:              }
  94:          }
  95:   
  96:          private string GetConnectionString()
  97:          {
  98:              SqlConnectionStringBuilder connectionString = 
  99:                  new SqlConnectionStringBuilder();
 100:              connectionString.IntegratedSecurity = true;
 101:              connectionString.InitialCatalog = databaseName.Text;
 102:              connectionString.DataSource = serverName.Text;
 103:              return connectionString.ConnectionString;
 104:          }
 105:   
 106:          private void databaseSync_ScriptExecuting(object sender, 
 107:              PerpetuumSoft.DataModel.ScriptExecuteEventArgs e)
 108:          {
 109:              log.AppendLine(e.Text);
 110:          }
 111:   
 112:          private void databaseSync_DatabaseUpdating(object sender, 
 113:              PerpetuumSoft.DataModel.DatabaseUpdatingEventArgs e)
 114:          {
 115:              log.Append("Begin synchronize: [");
 116:              log.Append(DateTime.Now.ToLongTimeString());
 117:              log.AppendLine("]");
 118:          }
 119:   
 120:          private void databaseSync_DatabaseUpdated(object sender, EventArgs e)
 121:          {
 122:              log.Append("End synchronize: [");
 123:              log.Append(DateTime.Now.ToLongTimeString());
 124:              log.Append("]");
 125:          }
 126:   
 127:          private void clearDbButton_Click(object sender, EventArgs e)
 128:          {
 129:              try
 130:              {
 131:                  log = new StringBuilder();
 132:   
 133:                  Database sourceDB = Database.CreateDatabaseWithSystemObjects();
 134:                  databaseSync.UpdateDatabase(sourceDB, GetConnectionString());
 135:   
 136:                  logTextBox.Text = log.ToString();
 137:              }
 138:              catch (Exception ex)
 139:              {
 140:                  logTextBox.Text = log.ToString();
 141:                  logTextBox.Text += ex.ToString();
 142:              }
 143:          }
 144:   
 145:          private void viewScriptsButton_Click(object sender, EventArgs e)
 146:          {
 147:              try
 148:              {
 149:                  log = new StringBuilder();
 150:   
 151:                  MetaModel model = new AttributeMappingSource().
 152:                      GetModel(typeof(DataClassesDataContext));
 153:                  Database sourceDB = dbBuilder.CreateDatabase(model);
 154:                  DatabaseSynchronizer dbSynchronizer = 
 155:                      databaseSync.Compare(sourceDB, 
 156:                      databaseSync.ReverseDatabase(GetConnectionString()));
 157:                  foreach (Script script in dbSynchronizer.Scripts)
 158:                  {
 159:                      log.AppendLine(script.GetText());
 160:                  }
 161:                  logTextBox.Text = log.ToString();
 162:              }
 163:              catch (Exception ex)
 164:              {
 165:                  logTextBox.Text = log.ToString();
 166:                  logTextBox.Text += ex.ToString();
 167:              }
 168:          }
 169:   
 170:      }
 171:  }

The most important lines above are these

   1:  MetaModel model = new AttributeMappingSource().
   2:     GetModel(typeof(DataClassesDataContext));
   3:  Database sourceDB = dbBuilder.CreateDatabase(model);
   4:  databaseSync.UpdateDatabase(sourceDB, GetConnectionString());

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This example is using a LINQ to SQL file as the database schema that is the one that forms the applications model at runtime. So this one will be the source of the comparison against the underlying database when a resynch is performed. It can be seen that this model (LINQ to SQL) has 3 tables in existence. These tables already exist in the underlying Northwind database.

image

Here they are

image

But the in the code that associated with the form, that I showed earlier, there is a new Function created entitled "ProductsUnderThisUnitPrice" which doesn’t exist in the underlying Northwind database.

So running the application shows us this new Function being created by the Database Restyle component.

image

Well that’s all well and good but did it actually create this in the underlying database?

image

The answer is yes.

So using the demo code, I decided to do something radical and clear the database, and then do a re-synchronization. And that worked as well. You can see below that there is a bunch of SQL generated to DROP tables/constraints etc etc

image

And going back to SQL we can see these tables are no longer within the Northwind database.

image

I then hit the Synchronize button, went back to SQL Server, and bingo all was back again. Here is what the component produces by way of script to re-create the schema again.

 

   1:  Begin synchronize: [08:49:24]
   2:   
   3:  CREATE TABLE [dbo].[Categories]([CategoryID] INT NOT NULL IDENTITY(1,1),
   4:  [CategoryName] NVARCHAR(15) NOT NULL ,[Description] NTEXT NULL ,[Picture] IMAGE NULL )
   5:   
   6:  ALTER TABLE [dbo].[Categories] ADD CONSTRAINT [PK_Categories] PRIMARY KEY 
   7:  NONCLUSTERED ([CategoryID] ASC)  WITH(PAD_INDEX = OFF,IGNORE_DUP_KEY = OFF,
   8:  STATISTICS_NORECOMPUTE = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON)
   9:   
  10:  CREATE TABLE [dbo].[Products]([ProductID] INT NOT NULL IDENTITY(1,1),
  11:  [ProductName] NVARCHAR(40) NOT NULL ,[SupplierID] INT NULL ,[CategoryID] INT NULL ,
  12:  [QuantityPerUnit] NVARCHAR(20) NULL ,[UnitPrice] MONEY NULL ,[UnitsInStock] SMALLINT NULL ,
  13:  [UnitsOnOrder] SMALLINT NULL ,[ReorderLevel] SMALLINT NULL ,[Discontinued] BIT NOT NULL )
  14:   
  15:  ALTER TABLE [dbo].[Products] ADD CONSTRAINT [PK_Products] 
  16:  PRIMARY KEY NONCLUSTERED ([ProductID] ASC)  
  17:  WITH(PAD_INDEX = OFF,IGNORE_DUP_KEY = OFF,STATISTICS_NORECOMPUTE = OFF,
  18:  ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON)
  19:   
  20:  CREATE TABLE [dbo].[Suppliers]([SupplierID] INT NOT NULL IDENTITY(1,1),
  21:  [CompanyName] NVARCHAR(40) NOT NULL ,[ContactName] NVARCHAR(30) NULL ,
  22:  [ContactTitle] NVARCHAR(30) NULL ,[Address] NVARCHAR(60) NULL ,[City] NVARCHAR(15) NULL ,
  23:  [Region] NVARCHAR(15) NULL ,[PostalCode] NVARCHAR(10) NULL ,[Country] NVARCHAR(15) NULL ,
  24:  [Phone] NVARCHAR(24) NULL ,[Fax] NVARCHAR(24) NULL ,[HomePage] NTEXT NULL )
  25:   
  26:  ALTER TABLE [dbo].[Suppliers] ADD CONSTRAINT [PK_Suppliers] 
  27:  PRIMARY KEY NONCLUSTERED ([SupplierID] ASC)  WITH(PAD_INDEX = OFF,IGNORE_DUP_KEY = OFF,
  28:  STATISTICS_NORECOMPUTE = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON)
  29:   
  30:  ALTER TABLE [dbo].[Products] WITH CHECK ADD CONSTRAINT [Category_Product] 
  31:  FOREIGN KEY (CategoryID) REFERENCES [dbo].[Categories] (CategoryID)  
  32:  ON UPDATE NO ACTION ON DELETE NO ACTION
  33:   
  34:  ALTER TABLE [dbo].[Products] WITH CHECK ADD CONSTRAINT [Supplier_Product] 
  35:  FOREIGN KEY (SupplierID) REFERENCES [dbo].[Suppliers] (SupplierID)  
  36:  ON UPDATE NO ACTION ON DELETE NO ACTION
  37:   
  38:  CREATE FUNCTION [dbo].[ProductsUnderThisUnitPrice]()
  39:                      RETURNS int
  40:                      AS
  41:                      BEGIN
  42:                         DECLARE @retval int
  43:                         SELECT @retval = COUNT(*) FROM Territory
  44:                         RETURN @retval
  45:                      END;
  46:  End synchronize: [08:49:24]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

And here is a screen shot after the Synchronize .

image

Cool huh.

Perpetuumsoft also claim to support other schemas apart from using LINQ to SQL.

All in all a very nice easy to use product I think. This is one that I think is actually fairly useful (that’s why I bothered to blog about it), and I shall be pushing to use whenever I get back to working with SQL Server.

 

Here is Perpetuumsoft web site, if you want to download it and play for yourself http://www.perpetuumsoft.com

CodeProject, Introduction

All New .NET 3.5 3D Elements

I have started looking at 3D again in WPF. I have in the past blogged about the Viewport2DVisual3D 3D WPF element. Well for what I am working on I didn’t need to be able to put 2D interactive elements on a 3D surface, but I did want the 3D object to able to respond to Mouse events.  Now in the past what you would have done is use a MouseDown event on the Viewport3D and do some sort of hit testing. Which was ok….

But now there is the wonderful new .NET 3.5 element ModelUIElement3D which is a fully fledges element that supports events. Hooray.

And there is also a new container element to host 1 or more ModelUIElement3D  elements.

Lets see an example

<Window x:Class="Shapes.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Shapes"
    Title="Window1" Height="610.122" Width="633.46">

    <Window.Resources>

        <!-- The 3D cube -->
        <MeshGeometry3D x:Key="CubeMesh"
            TriangleIndices = "0,1,2     2,3,0
                               4,7,6     6,5,4
                               8,11,10   10,9,8
                               12,13,14  14,15,12
                               16,17,18  18,19,16
                               20,23,22  22,21,20"

             Positions      = "-1,-1,1   -1,-1,-1  1,-1,-1  1,-1,1
                               -1,1,1    -1,1,-1   1,1,-1   1,1,1
                               -1,-1,1   -1,1,1    1,1,1    1,-1,1
                               -1,-1,-1  -1,1,-1   1,1,-1   1,-1,-1
                               -1,-1,1   -1,1,1   -1,1,-1  -1,-1,-1
                                1,-1,1    1,1,1    1,1,-1   1,-1,-1" />
    </Window.Resources>

    <Viewport3D>

        <Viewport3D.Camera>
            <PerspectiveCamera x:Name="camera" Position="-2,2,5"
                               LookDirection="2,-2,-5" FieldOfView="90" />
        </Viewport3D.Camera>

        <!-- Container for 3D Elements -->
        <ContainerUIElement3D x:Name="container">
            <ContainerUIElement3D.Transform>
                <RotateTransform3D>
                    <RotateTransform3D.Rotation>
                        <AxisAngleRotation3D Axis="0, 1, 0" Angle="0" />
                    </RotateTransform3D.Rotation>
                </RotateTransform3D>
            </ContainerUIElement3D.Transform>

            <!-- A fully Fledged 3d element complete with routed events -->
            <ModelUIElement3D MouseDown="Cube1_MouseDown">
                <ModelUIElement3D.Transform>
                    <Transform3DGroup>
                        <TranslateTransform3D OffsetZ="1.5" />
                        <RotateTransform3D>
                            <RotateTransform3D.Rotation>
                                <AxisAngleRotation3D Axis="0, 1, 0" Angle="0" />
                            </RotateTransform3D.Rotation>
                        </RotateTransform3D>
                    </Transform3DGroup>
                </ModelUIElement3D.Transform>
                <ModelUIElement3D.Model>
                    <GeometryModel3D Geometry="{StaticResource CubeMesh}">
                        <GeometryModel3D.Material>
                            <DiffuseMaterial x:Name="cube1Material" Brush="Blue" />
                        </GeometryModel3D.Material>
                    </GeometryModel3D>
                </ModelUIElement3D.Model>
            </ModelUIElement3D>
        </ContainerUIElement3D>

        <ModelVisual3D>
            <ModelVisual3D.Content>
                <DirectionalLight Color="White" Direction="-1,-1,-1"/>
            </ModelVisual3D.Content>
        </ModelVisual3D>

    </Viewport3D>

</Window>

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
And here is the C# code that has the event for the ModelUIElement3D

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Windows;
   6:  using System.Windows.Controls;
   7:  using System.Windows.Data;
   8:  using System.Windows.Documents;
   9:  using System.Windows.Input;
  10:  using System.Windows.Media;
  11:  using System.Windows.Media.Animation;
  12:  using System.Windows.Media.Media3D;
  13:  using System.Windows.Media.Imaging;
  14:  using System.Windows.Navigation;
  15:  using System.Windows.Shapes;
  16:  
  17:  namespace Shapes
  18:  {
  19:      /// <summary>
  20:      /// Interaction logic for Window1.xaml
  21:      /// </summary>
  22:      public partial class Window1 : Window
  23:      {
  24:  
  25:  
  26:          public Window1()
  27:          {
  28:              InitializeComponent();
  29:          }
  30:  
  31:  
  32:          /// <summary>
  33:          /// 3d Element Mouse Event, Neat
  34:          /// </summary>
  35:          private void Cube1_MouseDown(object sender, MouseButtonEventArgs e)
  36:          {
  37:              ModelUIElement3D currentObject = sender as ModelUIElement3D;
  38:              if (currentObject.Transform is Transform3DGroup)
  39:              {
  40:                  RotateTransform3D rotateTrans = null;
  41:  
  42:                  Transform3DGroup transGroup =
  43:                      currentObject.Transform as Transform3DGroup;
  44:                  rotateTrans = TryFindChild<RotateTransform3D>(transGroup);
  45:                  if (rotateTrans != null)
  46:                  {
  47:                      // spin the object around
  48:                      DoubleAnimation doubleAnimation =
  49:                          new DoubleAnimation(0,360,
  50:                          new Duration(TimeSpan.FromSeconds(0.5)));
  51:                      rotateTrans.Rotation.BeginAnimation(
  52:                          AxisAngleRotation3D.AngleProperty, doubleAnimation);
  53:                  }
  54:              }
  55:          }
  56:  
  57:  
  58:          /// <summary>
  59:          /// Try and find child of type T in the Transform3DGroup
  60:          /// </summary>
  61:          public static T TryFindChild<T>(Transform3DGroup parent)
  62:            where T : DependencyObject
  63:          {
  64:              foreach (DependencyObject child in parent.Children)
  65:              {
  66:                  if (child is T)
  67:                  {
  68:                      return child as T;
  69:                  }
  70:              }
  71:              return null;
  72:          }
  73:  
  74:  
  75:      }
  76:  }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }And that is all there is to it. So in this example if the cube gets a MouseDown I lookup its RotateTransform3D and spin it around by 360 degrees.

image

And here is a zip file with the demo project code 3dElements.zip

WPF

A Really Really Nice WPF App

I am now lucky enough to be working with WPF. I know a few things about WPF, but I am always looking out for stuff written / blogged about by the WPF master, and a personal friend of mine, Mr Josh Smith.

A while back he published an article at codeproject called Podder, which managed podcasts. It was very nice and used what he called structural skinning based around routed WPF commands, and the MVC pattern. Which was a first let me tell you.

Some of you may not know but Josh also works for a place called Infragistics (the UI people), and as such he has the pleasure of working with some truly talented (think Michael Angelo talented) UI designers/programmers. I think they have 7 MVPs there or something like that.

Anyway, one of the talented chaps there, has re-skinned Joshs original Podder app, and made it look like this. This is all thanks to Joshs original structural skinning idea.

image

I mean how cool is that. You owe it to yourself to read how this beauty works, I urge you all to read about it at the Podder2 article page and also at Joshs own blog

Nice one Josh. Respect

CodeProject, WPF

Explicitly Updating And Validating Databindings In WPF

The other day I was working on something for a Codeproject article, where I needed to bind part of my UI to an underlying data object. I want to use all the good validation thing such as a Validation Style to use for my TextBox, and also the use of the new .NET 3.5 interface IDataErrorInfo.

So that was fine. But I also wanted to allow the user to either apply the changes or cancel them. When the user chooses to apply the changes, the changes should be made Explicitly to the underlying data object, and ONLY update database if the underlying data object is in a valid state.

So how do we do that. Well the first thing to do is make sure we have a data object that provides validation using the .NET 3.5 interface IDataErrorInfo.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.ComponentModel;
   6:  
   7:  namespace Binding.Explicit
   8:  {
   9:      class Person : IDataErrorInfo
  10:      {
  11:          #region Data
  12:          private StringBuilder combinedError
  13:              = new StringBuilder(2000);
  14:          #endregion
  15:  
  16:          #region Ctor
  17:          public Person ()
  18:          {
  19:  
  20:          }
  21:          #endregion
  22:  
  23:          #region Public Properties
  24:          public int Age { get; set; }
  25:          #endregion
  26:  
  27:          #region IDataErrorInfo Members
  28:  
  29:          /// <summary>
  30:          /// Return the full list of validation 
  31:          /// errors for this object
  32:          /// </summary>
  33:          public string Error
  34:          {
  35:              get
  36:              {
  37:                  return combinedError.ToString();
  38:              }
  39:          }
  40:  
  41:          /// <summary>
  42:          /// Validates a particular column, and returns a 
  43:          /// string representing the current error
  44:          /// </summary>
  45:          /// <param name="columnName">The property name to 
  46:          /// validate</param>
  47:          /// <returns>A string representing the 
  48:          /// current error</returns>
  49:          public string this[string columnName]
  50:          {
  51:              get
  52:              {
  53:                  string result = null;
  54:  
  55:                  //basically we need a case for each property you 
  56:                  //wish to validate
  57:                  switch (columnName)
  58:                  {
  59:                      case "Age":
  60:                          if (Age < 0)
  61:                          {
  62:                              result = "Age cant be < 0";
  63:                              combinedError.Append (result + "rn");
  64:                          }
  65:                          if (Age > 20)
  66:                          {
  67:                              result = "Age cant be > 20";
  68:                              combinedError.Append(result + "rn");
  69:                          }
  70:                          break;
  71:                  }
  72:                  return result;
  73:              }
  74:          }
  75:  
  76:          #endregion
  77:      }
  78:  }

Then we need to create some items that will use these bindings (only “Age” in this simple case)

   1:  <Window x:Class="Binding.Explicit.Window1"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      Title="Window1" Height="300" Width="300">
   5:  
   6:      <Window.Resources>
   7:  
   8:          <Style x:Key="textStyleTextBox" TargetType="TextBox">
   9:              <Setter Property="Foreground" Value="#333333" />
  10:              <Style.Triggers>
  11:                  <Trigger Property="Validation.HasError" Value="true">
  12:                      <Setter Property="ToolTip"
  13:                          Value="{Binding 
  14:                          RelativeSource={RelativeSource Self},
  15:                          Path=(Validation.Errors)[0].ErrorContent}"/>
  16:                  </Trigger>
  17:              </Style.Triggers>
  18:          </Style>
  19:  
  20:      </Window.Resources>
  21:  
  22:      <StackPanel Orientation="Vertical">
  23:          <Label Content="Age" Width="auto" Height="auto"/>
  24:          <TextBox x:Name="txtAge" Width="auto" Height="auto"
  25:                   Style="{StaticResource textStyleTextBox}"
  26:                   Text="{Binding Path=Age, 
  27:                          UpdateSourceTrigger=Explicit,
  28:                          ValidatesOnDataErrors=True}"/>
  29:          <StackPanel Orientation="Horizontal">
  30:              <Button x:Name="btnUpdate" Content="Update Object"
  31:                      Width="auto" Height="auto" Click="btnUpdate_Click"/>
  32:              <Button x:Name="btnCancel" Content="Cancel"
  33:                      Width="auto" Height="auto" Click="btnCancel_Click"/>
  34:          </StackPanel>
  35:      </StackPanel>
  36:  </Window>

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }Also notice that within this XAML is a Style that is used by the bound TextBox. This Style creates a red rectangle around the bound TextBox and the appropriate tooltip, when the bound object is in an invalid state (basically when Validation.HasError is true.

Also notice that because part of my requirements, was to be able to choose to update the underlying object or cancel any changes, I am using the “UpdateSourceTrigger=Explicit” within the Binding expression.

So as you can probably imagine, the last part is to do the code behind, where we actually do the binding update Explicitly (manually). So let’s see that shall we

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.Windows;
   6:  using System.Windows.Controls;
   7:  using System.Windows.Data;
   8:  using System.Windows.Documents;
   9:  using System.Windows.Input;
  10:  using System.Windows.Media;
  11:  using System.Windows.Media.Imaging;
  12:  using System.Windows.Navigation;
  13:  using System.Windows.Shapes;
  14:  using System.ComponentModel;
  15:  
  16:  namespace Binding.Explicit
  17:  {
  18:      /// <summary>
  19:      /// Interaction logic for Window1.xaml
  20:      /// </summary>
  21:      public partial class Window1 : Window
  22:      {
  23:          public Window1()
  24:          {
  25:              InitializeComponent();
  26:              //Create a single Person to be used as the DataContext
  27:              this.DataContext = new Person();
  28:          }
  29:  
  30:          /// <summary>
  31:          /// Manually update the Binding SOurce, and see if its in a valid state.
  32:          /// If its not need to mark bindind as Invalid
  33:          /// </summary>
  34:          private void btnUpdate_Click(object sender, RoutedEventArgs e)
  35:          {
  36:              BindingExpression expression =
  37:                  txtAge.GetBindingExpression(TextBox.TextProperty);
  38:              expression.UpdateSource();
  39:  
  40:              string errorMessage = string.Empty;
  41:              if (!IsValid("Age", out errorMessage))
  42:              {
  43:                  ValidationError error = new ValidationError(
  44:                      new ExceptionValidationRule(),
  45:                      expression, errorMessage, null);
  46:                  Validation.MarkInvalid(expression, error);
  47:              }
  48:              else
  49:              {
  50:                  MessageBox.Show("Success, we could update DB here",
  51:                      "Success", MessageBoxButton.OK,
  52:                      MessageBoxImage.Information);
  53:              }
  54:          }
  55:  
  56:          /// <summary>
  57:          /// Attempts to see if the underlying data objects
  58:          /// bound property is in a valid state. The 
  59:          /// errorMessage parameter is also filled in by the
  60:          /// underlying data object
  61:          /// </summary>
  62:          /// <param name="path">The property to validate</param>
  63:          /// <param name="errorMessage">The errorMessage that the
  64:          /// unlerlying bound data object will fill in</param>
  65:          /// <returns>True if the underlying bound object is valid</returns>
  66:          private bool IsValid(string path, out string errorMessage)
  67:          {
  68:              errorMessage=((IDataErrorInfo)this.DataContext)[path];
  69:              return string.IsNullOrEmpty(errorMessage);
  70:          }
  71:  
  72:          /// <summary>
  73:          /// Exit, you could do something else if you wanted to
  74:          /// </summary>
  75:          private void btnCancel_Click(object sender, RoutedEventArgs e)
  76:          {
  77:              this.Close();
  78:          }
  79:  
  80:      }
  81:  }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }And that’s it, which gives us this sort of thing

db

Here is a small demo project should you wish to have the source code : bindingexplicit.zip

Introduction

A Really Cheesy Blog Entry (But I just don’t care)

Now I own a lot of programming books. And pretty much without fail, in the front of these monolithic manuals is a short praise for the authors wife/kids dogs etc etc. Now you have to ask your self how romantic that is. I mean being thanked in the front of a geek bible just wouldn’t/shouldn’t cut it in the romance stakes. Shame guy.

None the less they all do it, go check some out, they all have it there somewhere, bold as brass. I have to say I think this is pure cheese.

But something happened to me this week, my beautiful girl asked me to marry her, and I accepted. Leap year thing apparently. I didn’t know that, and thought it was a big joke, not quite the reaction she was expecting, but I soon realised the error of my ways, and quickly accepted.

And I felt I just had to write a little about it, as it’s a good thing, which I feel I want to share. So I can see why these reference manual authors do it now, it’s something you feel good about that you don’t mind people seeing. That’s my new opinion any how.

I first met my lady 10 years ago, when I had been single for more time than I care to remember, I had basically almost decided to become a monk, and had certainly given up hope in all woman of the species. But then as luck would have it I found someone that that was daft enough to like me as much as I liked her, and bada bing, bada boom, I found a girl to share my room. And have now ended up being with my girl for 10 years now.

Sarah has been a constant source of support for me through some good and not so good times. She is my rock. And without her, I strongly believe I would have ended up having a different path in life, a somewhat more self destructive one, and ended up in all sorts of bother. She made sure that didn’t happen. I have now become a more rounded individual, this is all down to me girl, basically she’s the raddest thing since sliced bread…And I just want to let you all know that.

I basically have no idea how many people read this blog, or whether this is a good / bad thing or maybe too personal a thing for a blog, I just don’t know…But since it’s my blog I’m just going to do what I like.

Heres me and my girl Sarah, babe you rock.

happy2.png

And heres some more

happy.png

So if you are out there and don’t have one of these here girl things, I reckon you should give them a go, they are pretty cool