21 Aralık 2023 Perşembe

Örnek DI uygulaması 6 - Displayer'leri kaldırıp bir adet generic displayer oluşturmak.

 Kod kalitemizi bir adım daha ilerleteceğiz. Bu küçük ama projeyi çok sadeleştirecek bir adım olacak. Gördüğümüz gibi her tablomuz için bir TFrame oluşturuyoruz, ancak her TFrame için de onu içinde barındıracak bir zarf oluşturmak zorunda kalıyoruz. Peki bunu bir tane yapıp parametrelerini değiştirerek çalışır hale getirebilir miyiz?

Bu yazının konusu da bu işi yapmak olacak!

Öncelikle View.MyBaseFrame.pas unit'inde şu eklemeyi yapıyoruz. Bu bize daha sonra oluşturacağımız Displpayer'da yardımcı olacak bir tanımlama:

...
  TframeMyBaseClass = class of TframeMyBase;
...
Sonrasında uEntityDisplayer.pas adlı bir unit ekleyelim projeye. İçinde şunlar olacak
unit uEntityDisplayer;

interface
uses System.Classes, uInterfaces, Vcl.Controls, Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.Forms, View.MyBaseFrame;

type
  TEntityDisplayer<T : TframeMyBase, constructor> = class(TInterfacedObject, IDisplayOnTabSheetGeneric)
  public
    procedure DisplayOnTabSheet(const aTabSheet: TTabSheet);
  end;

implementation

{ TEntityDisplayer }

procedure TEntityDisplayer<T>.DisplayOnTabSheet(const aTabSheet: TTabSheet);
var frm : TFrame;
begin
  frm := T(TframeMyBaseClass(T).Create(Application.MainForm));
  frm.Parent := aTabSheet;
  frm.Align := alClient;
  aTabSheet.Caption := (frm as T).GetCaption;
end;

end.
Diğer 3 adet displayer projeden çıkarılacak ve dosyalar diskten silinecek. Yanlışlıkla onların işlem görmesini istemeyiz.

Son olarak ta uRegistration değiştirilecek

unit uRegistration;

interface

uses
  Spring.Container, uInterfaces;

procedure RegisterInterfaces(aMyConnection : IMyConnection);

implementation
uses
    uEntityDisplayer
   ,View.Inventories
   ,View.Customers
   ,View.Suppliers
    ;

procedure RegisterInterfaces(aMyConnection : IMyConnection);
begin
  GlobalContainer.RegisterType<IDisplayOnTabSheet, TEntityDisplayer<TframeInventories>>('inventories');
  GlobalContainer.RegisterType<IDisplayOnTabSheet, TEntityDisplayer<TframeCustomers>>('customers');
  GlobalContainer.RegisterType<IDisplayOnTabSheet, TEntityDisplayer<TframeSuppliers>>('suppliers');


  GlobalContainer.RegisterInstance<IMyConnection>(aMyConnection, 'connection');

  GlobalContainer.Build;
end;

end.
Evet bundan sonra F9 yaptığımızda uygulamamız çalışacaktır.

Böylece her ekran için ayrı bir unit ve class oluşturma işinden sıyırmış olduk. Bu bizim daha sonra ekleyeceğimiz ekranlara ilişkin işlemleri hiç değiştirmeye gerek kalmadan yaptığımız bir sadeleştirme oldu.


Projenin bu şeklini şu linkten elde edebilirsiniz : DITest-5
























































Örnek DI uygulaması 5 - Frame'lerin bir PageControl üzerinde çoklu gösterimi

 Önceki yazıdaki son durum üzerine şimdi ana ekrandaki sağ kısımda yer alan pnlForClientFrames adlı TPanel bileşenini kaldırıp yerine bir TPageControl bileşeni koyacağız. İsterseniz de TMoPageControl adlı benim üzerinde bir küçük ekleme yaptığım bileşeni kullanabilirsiniz. Bunun ek özelliği her sayfayı kapatmak için, üstteki tab başlığının sağında bir kapat düğmesi olmasıdır (x). Bu düğmenin bazı sayfaları kapatması engellenebilir. Koyduğumuz bu bileşenin adına pagesForFrames diyeceğim ben.

Yine formun üzerine bir TSplitter koyalım ve bunun Align=alLeft yapalım ardından pagesForFrames için Align=alClient yapalım.

Böylelikle şimdilik ana forma amacımıza uygun şekli vermiş oluyoruz. 

uInterfaces.pas kodunu açıp orada IDisplayOnPanel'i değiştirelim.

  IDisplayOnTabSheet = interface
    ['{B28B9829-CBF3-4629-9C3F-E3859497A185}']
    procedure DisplayOnTabSeet(const aTabSheet: TTabSheet);
  end;
Sonra 3 adet displayer'i buna uygun olarak değiştireceğiz.
unit uCustomersDisplayer;

interface
uses System.Classes, uInterfaces, Vcl.Controls, Vcl.ExtCtrls, View.Customers, Vcl.ComCtrls;

type
  TCustomersDisplayer = class(TInterfacedObject, IDisplayOnTabSheet)
  public
    procedure DisplayOnTabSheet(const aTabSheet: TTabSheet);
  end;

implementation

{ TCustomersDisplayer }

procedure TCustomersDisplayer.DisplayOnTabSheet(const aTabSheet: TTabSheet);
var frm : TframeCustomers;
begin
  frm := TframeCustomers.Create(aTabSheet);
  frm.Parent := aTabSheet;
  frm.Align := alClient;
end;

end.
Diğer 2 unit de buna benzer şekilde değiştirilecek.
Daha sonra sıra uRegistration.pas'a geliyor. Ondaki kayıt cümleciklerini de şu şekilde değiştireceğiz.
unit uRegistration;

interface

uses
  Spring.Container, uInterfaces;

procedure RegisterInterfaces(aMyConnection : IMyConnection);

implementation
uses
      uInventoriesDisplayer
    , uCustomersDisplayer
    , uSuppliersDisplayer
    ;

procedure RegisterInterfaces(aMyConnection : IMyConnection);
begin
  GlobalContainer.RegisterType<IDisplayOnTabSheet, TInventoriesDisplayer>('inventories');
  GlobalContainer.RegisterType<IDisplayOnTabSheet, TCustomersDisplayer>('customers');
  GlobalContainer.RegisterType<IDisplayOnTabSheet, TSuppliersDisplayer>('suppliers');


  GlobalContainer.RegisterInstance<IMyConnection>(aMyConnection, 'connection');

  GlobalContainer.Build;
end;

end.
Ve son olarak da View.MainForm'da değişiklik yapacağız. Oradaki IDisplayOnPanel'i IDisplayOnTabSheet olarak değiştireceğiz. Ve elbette bir iki ek daha olacak. Önce ats adlı TabSheet yaratıyoruz ve bunun PageControl'ü olarak pagesForFrames'i atıyoruz. ve DisplayOnTabSheet'e parametre olarak veriyoruz, son olarak ta PageControl'ün aktif sayfası haline getiriyoruz. Yani son
bastığımız sayfa öne çıkıyor.
procedure TMainForm.ViewClientFrame(const aFrameName: string);
var
  iScr : IDisplayOnTabSheet;
  ats : TTabSheet;
begin
  ats := TTabSheet.Create(pagesForFrames);
  ats.PageControl := pagesForFrames;

  iScr := GlobalContainer.Resolve<IDisplayOnTabSheet>(aFrameName);
  iScr.DisplayOnTabSheet(ats);
  pagesForFrames.ActivePage := ats;
end;

Ama buradaki ekran görüntüsünde de gördüğümüz gibi tabların başlıklarında hiçbir şey yazmıyor, çünkü biz bir değer atamadık. Şimdi onu da yapalım.
Öncelikle ViewMyBaseFrame'deki TframeMyBase'e bir virtual, abstract metot ekleyeceğiz.
...
...
    function GetCaption : string; virtual; abstract;
  end;
...
Amacımız bundan türetilen ekranlarda, bu metodun override edilmesini (ezilmesini) zorunlu kılarak her ekrana bir ekran adı verilmesini sağlamaktır. Bundan türeyen tüm ekranlar create edildiğinde eğer bu metodu override etmemişlerse program Abstract error verecektir ve açılmayacaktır.
unit View.Customers;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, View.MyBaseFrame, Data.DB, Vcl.Grids,
  Vcl.DBGrids, Vcl.ExtCtrls;

type
  TframeCustomers = class(TframeMyBase)
  private
    { Private declarations }
  protected
    function GetSqlClause : string; override;
  public
    function GetCaption : string; override;
  end;

var
  frameCustomers: TframeCustomers;

implementation

{$R *.dfm}

{ TframeCustomers }

function TframeCustomers.GetCaption: string;
begin
  Result := 'Müşteriler';
end;

function TframeCustomers.GetSqlClause: string;
begin
  Result := 'select * from Customer order by CustomerId';
end;

end.
Diğer ekranlarımız (View.Inventories, View.Suppliers) için de ayrı ayrı yapacağız aynı işi. 
Sonrasında tekrar Displayer'lerde değişiklik yapmamız gerekiyor.

...
procedure TCustomersDisplayer.DisplayOnTabSheet(const aTabSheet: TTabSheet);
var frm : TframeCustomers;
begin
  frm := TframeCustomers.Create(aTabSheet);
  frm.Parent := aTabSheet;
  frm.Align := alClient;
  aTabSheet.Caption := frm.GetCaption;
end;
Bu değişiklik diğer iki displayer'de de yapılmalı (uInventoriesDisplpayer.pas ve uSuppliersDisplayer.pas). 


Burada da görüldüğü gibi artık tab başlıklarını da yazıyor. 

Projenin bu şeklini şu linkten elde edebilirsiniz : DITest-4




































14 Aralık 2023 Perşembe

Örnek DI uygulaması 4-Frame'leri standart bir frame'den türetmek

 Bu zamana kadar gördüğümüz gibi, her frame'de aynı işlemleri yapıyoruz. Bunları tek bir ancestor (ata) TFrame'de yapsak ve diğer tüm frame'leri ondan türetsek nasıl olur;

Önce View.Inventories ve View.Customers unit'lerini projeden çıkaralım. Bunları ve dfm dosyalarını başka bir klasöre taşıyalım.

Daha sonra yeni bir TFrame unit'i ekleyelim ve bunu View.MyBaseFrame.pas adıyla kaydedelim. İçindeki frame'e frameMyBase adı verelim, üzerine 2 adet panel koyalım. Panel2'nin Align=alBottom ve Panel1'in Align=alClient yapalım. Her ikisinin de BevelOuter=bvNone ve Caption={boş} yapalım.

Panel1 üzerine bir DBGrid ve bir de DataSource koyalım. DBGrid'in Align=alClient, DataSource=DataSource1 yapalım. Ayrıca DBGrid'in ReadOnly=True, Options.RowSelect=True yapalım.

TframeMyBase şu şekilde olsun,

unit View.MyBaseFrame;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Data.DB,
  Vcl.Grids, Vcl.DBGrids,
  uInterfaces,
  Spring.Container;

type
  TframeMyBase = class(TFrame)
    Panel2: TPanel;
    Panel1: TPanel;
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
  private
  protected
    function GetSqlClause : string; virtual; abstract;
  public
    constructor Create(AOwner: TComponent);
    { Public declarations }
  end;

implementation

{$R *.dfm}

constructor TframeMyBase.Create(AOwner: TComponent);
var
  aConnection: IMyConnection;
begin
  inherited;
  aConnection := GlobalContainer.Resolve<IMyConnection>('connection', []);
  DataSource1.DataSet := aConnection.GetQuery(GetSqlClause);
end;

end.
Burada görüleceği üzere GetSqlClause adlı bir abstract fonksiyon tanımlandı. Bundan amaç buna burada bir değer vermeyeceğiz ancak bundan türetilen Frame'ler bu fonksiyonu ezerek değer atamak zorunda kalacaklardır. Bu şekilde sonuç View.Inventories ya da View.Customers gibi birimlerimizin her biri için ayrı ayrı hep aynı işlemleri yapmaktan kurtulmuş olacağız. Ayrıca Create yapılandırıcısını her biri için yazmamız da gerekmeyecek.

Şimdi ikinci aşama olarak File/New/Other/Inheritable Items/frameMyBase seçeceğiz ve yaptığımız bu Base frame'den yeni View'larımızı türeteceğiz. 
İlkini View.Inventories.pas adıyla save edelim ve frame adına frameInventories yazalım. Burada gördüğümüz gibi bu frame için Panel, DBGrid ve DataSource hazır geldi zaten karşımıza.
Bunda protected kısmında GetSqlClause fonksiyonunu yazmamız gerekiyor onu da şöyle yapalım:
unit View.Inventories;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, View.MyBaseFrame, Data.DB, Vcl.Grids,
  Vcl.DBGrids, Vcl.ExtCtrls;

type
  TframeInventories = class(TframeMyBase)
  private
    { Private declarations }
  protected
    function GetSqlClause : string; override;
  public
    { Public declarations }
  end;

var
  frameInventories: TframeInventories;

implementation

{$R *.dfm}

{ TframeInventories }

function TframeInventories.GetSqlClause: string;
begin
  Result := 'select * from InventoryItem order by InventoryItemId';
end;

end.
View.MyBaseFrame'den bir frame daha inherit edelim ve bunu da View.Customers olarak kaydedelim, frame adını frameCustomers yapalım. F9'a bastığımızda aynen çalışacaktır. Çünkü bunlar için diğer bağlantı kodlarını oluşturmuştuk.

Şimdi, daha önce oluşturmadığımız tedarikçiler ekranını ekleyelim projeye. Bu şekilde yeni bir view eklediğimizde ne yapmamız gerektiğini de gözden geçirmiş olalım.
İlk olarak biraz yukarıda anlatıldığı gibi, File/New/Other/Inheritable Items/frameMyBase seçerek türetilmiş frame'i oluşturalım. Bunu View.Suppliers.pas adıyla kaydedelim, frame'i frameSuppliers olarak adlandıralım ve
unit View.Suppliers;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, View.MyBaseFrame, Data.DB, Vcl.Grids,
  Vcl.DBGrids, Vcl.ExtCtrls;

type
  TframeSuppliers = class(TframeMyBase)
  private
    { Private declarations }
  protected
    function GetSqlClause : string; override;
  public
    { Public declarations }
  end;

var
  frameSuppliers: TframeSuppliers;

implementation

{$R *.dfm}

{ TframeSuppliers }

function TframeSuppliers.GetSqlClause: string;
begin
  Result := 'select * from Supplier order by SupplierId';
end;

end.
Daha sonra bunu konteyner'le bağlantısını kurmak üzere uSuppliersDisplayer.pas'ı oluşturalım

unit uSuppliersDisplayer;

interface
uses System.Classes, uInterfaces, Vcl.Controls, Vcl.ExtCtrls, View.Suppliers;

type
  TInventoriesDisplayer = class(TInterfacedObject, IDisplayOnPanel)
  public
    procedure DisplayOnPanel(const aPanel: TPanel);
  end;

implementation

{ TSuppliersDisplayer }

procedure TInventoriesDisplayer.DisplayOnPanel(const aPanel: TPanel);
var frm : TframeSuppliers;
begin
  frm := TframeSuppliers.Create(aPanel);
  frm.Parent := aPanel;
  frm.Align := alClient;
end;

end.

Üçüncü olarak uRegistration.pas'a bunu ekleyeceğiz.

unit uRegistration;

interface

uses
  Spring.Container, uInterfaces;

procedure RegisterInterfaces(aMyConnection : IMyConnection);

implementation
uses
      uInventoriesDisplayer
    , uCustomersDisplayer
    , uSuppliersDisplayer
    ;

procedure RegisterInterfaces(aMyConnection : IMyConnection);
begin
  GlobalContainer.RegisterType<IDisplayOnPanel, TInventoriesDisplayer>('inventories');
  GlobalContainer.RegisterType<IDisplayOnPanel, TCustomersDisplayer>('customers');
  GlobalContainer.RegisterType<IDisplayOnPanel, TSuppliersDisplayer>('suppliers');


  GlobalContainer.RegisterInstance<IMyConnection>(aMyConnection, 'connection');

  GlobalContainer.Build;
end;

end.
ve son olarak da, MainForm'da Tedarikçiler düğmesinin OnClick event'ini yazacağız.
procedure TMainForm.btnTedarikcilerClick(Sender: TObject);
begin
  ViewClientFrame('suppliers');
end;
Evet, her yeni view eklemede ne yapacağımızı standardize etmiş olduk artık. 
Şimdi sırada bunu daha da iyileştirebilir miyiz onun araştırması olacak! Ve ardından bu view'lara bağlı olarak insert-update-delete-view detail ekranlarının sisteme entegre edilmesi söz konusu edilecek.

Projenin bu şeklini şu linkten elde edebilirsiniz : DITest-3





Örnek DI uygulaması 3 - Projeye Müşterileri gösterecek yeni frame eklemek

 Bu aşamada her modül için bir uXxxDisplayer.pas ve bir View.Xxx.pas unit'lerini oluşturacağız. 

Önce View.Customers.pas'ı oluşturalım. Boş bir VCL Frame oluşturalım. Bunun üzerine 2 adet TPanel koyalım, Panel2'nin Align özelliği alBottom, Caption boş, Panel1'in Align özelliği alClient Caption boş olsun. Panel1 üzerine bir DBGrid koyalım, özelliklerini şu şekilde değiştirelim;

Align=alClient 

DataSource=DataSource1

ReadOnly=True

Options.dgEditing=False

Options.RowSelect=True

Frame adını TframeCustomers yapalım.

Create yapılandırıcısını ekleyelim

constructor TframeCustomers.Create(AOwner: TComponent);
var
  aConnection: IMyConnection;
begin
  inherited;
  aConnection := GlobalContainer.Resolve<IMyConnection>('connection', []);
  DataSource1.DataSet := aConnection.GetQuery('select * from Customer order by CustomerId');
end;

Şimdi uCustomerDisplayer.pas'ı oluşturalım.
unit uCustomersDisplayer;


interface
uses System.Classes, uInterfaces, Vcl.Controls, Vcl.ExtCtrls, View.Customers;

type
  TCustomersDisplayer = class(TInterfacedObject, IDisplayOnPanel)
  public
    procedure DisplayOnPanel(const aPanel: TPanel);
  end;

implementation

{ TInventoriesDisplayer }

procedure TCustomersDisplayer.DisplayOnPanel(const aPanel: TPanel);
var frm : TframeCustomers;
begin
  frm := TframeCustomers.Create(aPanel);
  frm.Parent := aPanel;
  frm.Align := alClient;
end;

end.
Son olarak uRegistration.pas ve View.MainForm.pas'ta eklemeler yapmamız gerekli.
uRegistration.pas şu şekli alacak.
unit uRegistration;

interface

uses
  Spring.Container, uInterfaces;

procedure RegisterInterfaces(aMyConnection : IMyConnection);

implementation
uses
      uInventoriesDisplayer
    , uCustomersDisplayer
    ;

procedure RegisterInterfaces(aMyConnection : IMyConnection);
begin
  GlobalContainer.RegisterType<IDisplayOnPanel, TInventoriesDisplayer>('inventories');
  GlobalContainer.RegisterType<IDisplayOnPanel, TCustomersDisplayer>('customers');

  GlobalContainer.RegisterInstance<IMyConnection>(aMyConnection, 'connection');

  GlobalContainer.Build;
end;

end.

MainForm'da Müşteriler butonunun OnClick event'ine şunları ekleyeceğiz. 

Bu işlemlerden sonra artık Müşteriler butonuna tıkladığımızda veritabanındaki Customer tablosunu View.Customers.pas'ta frameCustomers üzerindeki dbgridde görüntülenecektir.
Bu şeklinin kodlarını şu linkten indirebilirsiniz : DITest-2.rar













Örnek DI uygulaması 2-Projenin ve ana bağlantıların oluşturulması

Bu örneği çalıştırabilmek için MS SQL ve Delphi 10 ya da üzeri sürümler kullanmanız gerekmektedir. 

Öncelikle Delphi'de File - New - Windows VCL Application Delphi 'ye tıklayın. Bunun sonucunda yeni bir VCL uygulaması açılacaktır. Bunu DITest adlı bir klasöre yine aynı adlı proje olarak kaydediyoruz. Form'a View.MainForm adını vererek kaydediyoruz. 

Formun üzerine Tool Palette'den Toolbar, StatusBar ve 2 adet TPanel bırakıyoruz. Bunlardan bir panelin Alignment'ı taLeft yapıyoruz, sonra Tool Palette'den bir TSplitter bırakıyoruz formun üzerine ve bunun Alignment'ını da taLeft yapıyoruz. 

2. panelin Alignment'ını taClient yapıyoruz. 

Her iki panelin de Caption özelliğini boş yapıyoruz, yani yazan Panel1 ve Panel2'yi siliyoruz. Ayrıca ben BevelOuter özelliğini de None yapıyorum. 

Soldaki panel üzerine ToolPalette'den TCategoryPanelGroup bırakıyorum. Bunun üzerinde sağ klik yapıp New Panel'e basarak yeni grupçuklar yaratıyorum. Bunları da adlandırıyorum:

  • Stok İşlemleri
  • Alım Siparişleri
  • Alım İşlemleri
  • Satış Siparişleri
  • Satış İşlemleri
Elbette bunlar sadece örnek olarak varlar. Bunların üzerine pek çok madde eklenebilir.
Bu kategori panellerinin üzerinde Add Control/Button seçerek 4'er adet buton ekleyelim ve her birine ad verelim.

MainForm

Şimdi aradaki bağlantıları sağlayan kısımları oluşturmadan önce Frame'leri oluşturalım. Frame'i doğrudan Container'e bağlamayacağımız için onu başka bir sınıfla sarmalamalıyız. Bu sınıflar da her işlem ekranı için bir adet olmalı. Bunlar için öncelikle interface'leri oluşturalım.

unit uInterfaces;

interface
uses Vcl.ExtCtrls;

type
   IDisplayOnPanel = interface
    ['{F2D7E53B-5EB3-4A8F-A12D-E9C9A3F56874}']
    procedure DisplayOnPanel(const aPanel: TPanel);

  end;

implementation

end
Tabloları ekranda gösterecek tüm frame'ler bundan türetilmiş sınıfların içinde yer alacaklar. Bunun ardından stokları göstereceğimiz frame'i oluşturalım.

Önce projeye yeni bir VCL frame ekleyelim, üzerine 2 adet panel koyalım, Panel2'nin Align'ını alBottom ve Panel1'inkini alClient yapalım. Caption'larını kaldıralım, BevelOuter'larını bvNone yapalım.

Panel1'in üzerine bir DBGrid koyalım ve bunun bazı özelliklerini şu şekilde değiştirelim;
-ReadOnly=True
-Align=alClient
-Options.dgEditing=False
-Options.dgRowSelect=True

Frame'e bir TDataSource ekleyelim ve bunu DBGrid'in DataSource özelliğine bağlayalım. Yani
DBGrid1.DataSource := DataSource1;
Sonrasında DBGrid1 üzerine elle stok tablosundaki bazı alanları ekliyoruz (InventoryItemId, ItemCode, ItemName, SpecCode) ve bunların kolon genişliklerini ayarlıyoruz.

Stok liste frame'i


Şimdi bu frame'i sarmak için stok Displayer'ini oluşturalım:
unit uInventoriesDisplayer;

interface
uses System.Classes, uInterfaces, Vcl.Controls, Vcl.ExtCtrls;

type
  TInventoriesDisplayer = class(TInterfacedObject, IDisplayOnPanel)
  public
    procedure DisplayOnPanel(const aPanel: TPanel);
  end;

implementation

{ TInventoriesDisplayer }

procedure TInventoriesDisplayer.DisplayOnPanel(const aPanel: TPanel);
var frm : TframeInventories;
begin
  frm := TframeInventories.Create(aPanel);
  frm.Parent := aPanel;
  frm.Align := alClient;
end;

end.

Burada görüldüğü gibi DisplayOnPanel içerisinden Stok gridini içeren frame'i create ediyoruz ve MainForm'daki client frame'i içerecek olan Panel'in içine yerleştiriyoruz. Ancak datayla ilgili herhangi bir işlem yapmadık henüz.

Şimdi xxxDisplayer ve MainForm arasındaki bağlantıyı oluşturacak Container kaydını yapalım! Bunun için uRegistration adlı bir Unit oluşturacağız.

unit uRegistration;

interface

uses
  Spring.Container, uInterfaces;

procedure RegisterInterfaces;

implementation
uses
      uInventoriesDisplayer
    ;

procedure RegisterInterfaces;
begin
  GlobalContainer.RegisterType<IDisplayOnPanel, TInventoriesDisplayer>('inventories');

  GlobalContainer.Build;
end;

end.


ve bu RegisterInterfaces rutinini MainForm'un OnCreate olayında çağırmamız gerekiyor.

procedure TMainForm.FormCreate(Sender: TObject);
begin
  RegisterInterfaces;
end;
Ve Stoklar düğmesine bastığımızda yapacaği işlemleri de yazalım :
procedure TMainForm.btnStoklarClick(Sender: TObject);
begin
  ViewClientFrame('inventories');
end;

procedure TMainForm.ViewClientFrame(const aFrameName: string);
var
  iScr : IDisplayOnPanel;
  i : integer;
begin
  for i:=pnlForClientFrames.ControlCount-1 downto 0 do
    if pnlForClientFrames.Controls[i] is TFrame then
      pnlForClientFrames.Controls[i].Free;
  iScr := GlobalContainer.Resolve<IDisplayOnPanel>(aFrameName);
  iScr.DisplayOnPanel(pnlForClientFrames);
end;


Burada ViewClientFrame() adlı bir procedure oluşturduk ve event'den ekranın kayıt ismini vererek bunu çağırdık. Bunun nedeni bu işlemin her buton için tekrarlanacağıydı. Bunları tekrar tekrar yazmamak için bu şekilde yazdık.
Şimdi sırada DB connection kısmı var, onu da yazdığımızda çerçeveyi tamamlamış olacağız.
Bunun için önce uInterfaces.pas kod birimine şu interafce'i ekliyoruz;

  IMyConnection = interface
    ['{3AD307A1-E323-4A65-9AE7-B25436A5DC1F}']
    function GetQuery(aSql : String) : TDataset;
  end;

Ve ardından yeni bir Unit içinde bunun uygulamasını yazıyoruz :

unit uMyADOConnection;

interface

uses DB, ADODB, uInterfaces;

type
  TMyADOConnection = class(TInterfacedObject, IMyConnection)
  private
    fConnection : TADOConnection;
  public
    constructor Create(aConnection : TADOConnection);
    function GetQuery(const aSql : String) : TDataset;
  end;

implementation

{ TMyADOConnection }

constructor TMyADOConnection.Create(aConnection : TADOConnection);
begin
  inherited Create;
  fConnection := aConnection;
  fConnection.LoginPrompt := False;
  fConnection.Connected := True;
end;

function TMyADOConnection.GetQuery(const aSql: String): TDataset;
var
  aQuery : TADODataset;
begin
  aQuery := TADODataset.Create(fConnection);
  aQuery.Connection := fConnection;
  aQuery.CommandText := aSql;
  aQuery.Open;
  Result := aQuery;
end;

end.

uRegistration biriminde Connection ile ilgili düzeltmeler yapacağız.
unit uRegistration;

interface

uses
  Spring.Container, uInterfaces;

procedure RegisterInterfaces(aMyConnection : IMyConnection);

implementation
uses
      uInventoriesDisplayer
    ;

procedure RegisterInterfaces(aMyConnection : IMyConnection);
begin
  GlobalContainer.RegisterType<IDisplayOnPanel, TInventoriesDisplayer>('inventories');

  GlobalContainer.RegisterInstance<IMyConnection>(aMyConnection, 'connection');

  GlobalContainer.Build;
end;

end.
MainForm üzerine Tool Palette'den bir TADOConnection ekleyeceğiz. Bunun DB ile bağlantısını kurup OnCreate event'inde bazı değişiklikler yapacağız. 


procedure TMainForm.FormCreate(Sender: TObject);
begin
  myConnection := TMyAdoConnection.Create(ADOConnection1);
  RegisterInterfaces(myConnection);
end;
Son olarak ta View.Inventories.pas'ta yapılandırıcıyı buraya koyacağız ve sonunda şu şekle getireceğiz.

unit View.Inventories;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Vcl.Grids,
  Vcl.DBGrids, Vcl.ExtCtrls,
  Spring.Container,
  uInterfaces;

type
  TframeInventories = class(TFrame)
    Panel1: TPanel;
    Panel2: TPanel;
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
  private
    { Private declarations }
  public
    constructor Create(AOwner : TComponent); override;
  end;

implementation

{$R *.dfm}

{ TframeInventories }

constructor TframeInventories.Create(AOwner: TComponent);
var
  aConnection: IMyConnection;
begin
  inherited;
  aConnection := GlobalContainer.Resolve<IMyConnection>('connection', []); //<IMyConnection>;
  DataSource1.DataSet := aConnection.GetQuery('select * from InventoryItem order by InventoryItemId');
end;

end.
Bu halinin kodlarını şu linkten indirebilirsiniz : DITest kodları 









Örnek DI uygulaması 1-Veritabanı oluşturulması

Tüm bu örnekleri çalıştırabilmek için öncelikle örnek veritabanını oluşturmamız gerekiyor.

Bu nedenle gerekli 5 adet tabloyu çok kısa şekilde SQL yaratma cümleciklerini paylaşacağım. Bunları MS Sql Server Management Studio'da çalıştırırsanız veritabanınız oluşturulacaktır.

create db_sample;
use db_sample;

create table Customer(
  CustomerId integer not null identity(1,1) primary key,
  CustomerName nvarchar(100) null,
  AddressLine1 nvarchar(50) null,
  AddressLine2 nvarchar(50) null,
  AddressLine3 nvarchar(50) null,
  City nvarchar(50) null,
  Country nvarchar(50) null,
  PostCode nvarchar(20) null,
  ContactPerson nvarchar(50) null,
  Phone varchar(15) null,
  Fax varchar(15) null,
  ContactEMail nvarchar(100) null,
  CurrencyTypeId integer,
  TotalDebit float default 0,
  TotalCredit float default 0,
  Balance float default 0,
  PaymentDueDate integer default 0,
  InBlackList bit not null default 0,
  IsDeleted bit not null default 0,
  LastUpdatedDT datetime default getutcdate(),
  LastModifyingUser integer
);


insert into [dbSample].dbo.Customer 
(CustomerName, AddressLine1, AddressLine2, AddressLine3, City, Country, ContactPerson, Phone, Fax, ContactEMail) 
values
('Kart Dekorasyon Malzemeleri ve Müt.Hiz. A.Ş.', 'Bedesten Sok. Katmerli Han No:4/13 Kat:3', 'Karaköy', '', 'İstanbul', 'Türkiye', 'Ahmet Alagöz', '0532717717', '02127127272', 'a-alagoz@gmail.com'),
('Damak Şekercilik ve Pastacılık Ltd.', 'Limon Sok. Hacıoğlu Ap. No:12/1', 'Göztepe', '', 'İstanbul', 'Türkiye', 'Murat Yapan', '05327177818', '02127127273', 'muratyapan@damak.com.tr');

create table Supplier(
  SupplierId integer not null identity(1,1) primary key,
  SupplierName nvarchar(100) null,
  AddressLine1 nvarchar(50) null,
  AddressLine2 nvarchar(50) null,
  AddressLine3 nvarchar(50) null,
  City nvarchar(50) null,
  Country nvarchar(50) null,
  PostCode nvarchar(20) null,
  ContactPerson nvarchar(50) null,
  Phone varchar(15) null,
  Fax varchar(15) null,
  ContactEMail nvarchar(100) null,
  CurrencyTypeId integer,
  TotalDebit float default 0,
  TotalCredit float default 0,
  Balance float default 0,
  PaymentDueDate integer default 0,
  InBlackList bit not null default 0,
  IsDeleted bit not null default 0,
  LastUpdatedDT datetime default getutcdate(),
  LastModifyingUser integer
);

insert into Supplier 
(SupplierName, AddressLine1, AddressLine2, AddressLine3, City, Country, ContactPerson, Phone, Fax, ContactEMail) 
values
('Kartel Yemek ve İkram Üretim ve Satış A.Ş.', '', 'Ümraniye', '', 'İstanbul', 'Türkiye', 'Mehmet Yurdan', '0532717719', '02127127274', 'mehmetyurdan@gmail.com'),
('Alaylı Otomotiv San. ve Tic. A.Ş.', 'Yalı Cad. Nur Han No:15/44 Kat 4', 'Karaköy', '', 'İstanbul', 'Türkiye', 'Yelda Saran', '05327177819', '02127127275', 'yeldasaran@alayliotomotiv.com.tr');

create table InventoryItem(
  InventoryItemId integer not null identity(1,1) primary key,
  InventoryGroupId integer not null,
  MainSupplierId integer null,
  ItemCode nvarchar(30) not null,
  ItemName nvarchar(100) not null,
  SpecCode nvarchar(20) null,
  StoragePlace nvarchar(100) null,
  PictureFileName nvarchar(100) null,
  Measurements nvarchar(50) null,
  CurrencyTypeId integer null,
  BuyingPrice float null,
  SellingPrice float null,
  VatPercentage float null,
  TotalIncomingQtty float default 0,
  TotalOutgoingQtty float default 0,
  TotalIncomingAmount float default 0,
  TotalOutgoingAmount float default 0,
  OtvAmount float default 0,
  UnitDesc nvarchar(10) null,
  ReorderPoint float default 0,
  BufferStock float default 0,
  IsDeleted bit not null default 0,
  LastUpdatedDT datetime default getutcdate(),
  LastModifyingUser integer
);

insert into Inventory 
(InventoryGroupId, MainSupplierId, ItemCode, ItemName,                        SpecCode, StoragePlace, Measurements, CurrencyTypeId, BuyingPrice, SellingPrice, VatPercentage, OtvAmount, UnitDesc, ReorderPoint, BufferStock)
  values
(1,                0,              'KAG80-1',	  'Kağıt 80 gram 1. hamur',				 '',       'C18R5',      'A4,80gr',    null, 15,  19,  18, null, 'Paket', 100, 20),
(1, 0,							   'KAG90-1',	  'Kağıt 90 gram 1. hamur',				 '',       'C18R6',      'A4,90gr',    null, 20,  25,  18, null, 'Paket', 40, 5),
(2, 0,                             'DEFHMO160-3', 'Defter Harita Metot 1 orta 3. hamur', '',	   'C18R4',		 'B3,60yaprak',null, 10,  13,  18, null, 'Adet',  90, 10),
(3, 0,                             'RSKLSA3',     'Resim Kalemi Siyah A3',				 'kkk',    'R-B18',      '',           2,    1.2, 1.4, 18, null, 'Adet', 80, 10);


create table PurchaseInvoiceHeader(
  PurchaseInvoiceHeaderId integer not null identity(1, 1) primary key,
  InvoiceDate datetime not null,
  InvoiceNumber nvarchar(20),
  SupplierId integer not null,
  SpecCode nvarchar(20) null,
  InvDescription nvarchar(100) null,
  CurrencyTypeId integer,
  CurrencyRate float,
  TotalAmount float,
  VatPercentage1 float,
  VatAmount1 float,
  VatPercentage2 float,
  VatAmount2 float,
  VatPercentage3 float,
  VatAmount3 float,
  TotalOtvAmount float,
  DueDate integer default 0,
  Paid bit default 0,
  MailAddress1 nvarchar(50) NULL,
  MailAddress2 nvarchar(50) NULL,
  MailAddress3 nvarchar(50) NULL,
  MailCity nvarchar(50) NULL,
  MailCountry nvarchar(50) NULL,
  MailPostCode nvarchar(20) NULL,
  IsDeleted bit not null default 0,
  LastUpdatedDT datetime default getutcdate(),
  LastModifyingUser integer,
  CONSTRAINT FK_PurchaseInvoiceHeader_Supplier FOREIGN KEY (SupplierId)     
    REFERENCES Supplier (SupplierId)
);

create table SalesInvoiceHeader(
  SalesInvoiceHeaderId integer not null identity(1,1) primary key,
  InvoiceDate datetime not null,
  InvoiceNumber nvarchar(20),
  CustomerId integer not null,
  SpecCode varchar(20) null,
  InvDescription nvarchar(100) null,
  CurrencyTypeId integer,
  CurrencyRate float,
  TotalAmount float,
  VatPercentage1 float,
  VatAmount1 float,
  VatPercentage2 float,
  VatAmount2 float,
  VatPercentage3 float,
  VatAmount3 float,
  TotalOtvAmount float,
  DueDate integer default 0,
  Paid bit default 0,
  DeliveryAddress1 nvarchar(50) null,
  DeliveryAddress2 nvarchar(50) null,
  DeliveryAddress3 nvarchar(50) null,
  DeliveryCity nvarchar(50) null,
  DeliveryCountry nvarchar(50) null,
  DeliveryPostCode nvarchar(20) null,
  IsDeleted bit not null default 0,
  LastUpdatedDT datetime default getutcdate(),
  LastModifyingUser integer,
  CONSTRAINT FK_SalesInvoiceHeader_Customer FOREIGN KEY (CustomerId)     
    REFERENCES Customer (CustomerId)
);