Blog Archives

Handling with Connection String at Run-Time in developing desktop applications


Almost every desktop application deals with some kind of external memory to save data for further use. The most part of them, use a database. On the other hand an Application needs connection string to connect to the database, for handling its memory. So, how to use connection string and how to manipulate with it, that’s the question which this post wants to answer.

If we want to change the connection string during the application run-time, it is not a simple task, because the connection string is placed in to an application scope that is read only.

The reason why we need to change the connection string is the different settings and environment between users, as well as different environment between developer and end-user. So when we are planning application deployment we must have that in mind, and  provide the implementation custom modification of the connection string.

clip_image002

If we look files of an Application (for example on the picture above) we can see two exe file, and two corresponding configuration files. This is the .NET rule, that every exe file may have only one configuration file.

The structure of configuration file

clip_image004

The picture above shows content of the configuration file and the connection string data. .NET Application can access this data with the API placed in to System.Configuration namespace, by using specific XML schema developed by Microsoft for that purpose.

To access NorthwindConncetionString from the configuration file we can achieve that with the following code:

//Read connection string from configuration file
var connStringFromConfig = System.Configuration.ConfigurationManager.
ConnectionStrings["ConnStringDemo1.Properties.Settings.NorthwindConnectionString"];

If we want to change connection string, exception will throw with the following message:

clip_image005

So the question is how to change connection string anyway?

To change connection string we need to open configuration file with XML API functions, find the connection string and change the data manually then save changes back to file then restart the application. This is in short how to do that, the following code do exactly what we said before:

private bool ChangeConnectionString(string connStringName, string newValue)
{
 try
 {
 //CreateXDocument and load configuration file
 XDocument doc = XDocument.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

 //Find all connection strings
 var query1 = from p in doc.Descendants("connectionStrings").Descendants()
 select p;

 //Go throught each connection string elements find atribute specified by argument and replace its value with newVAlue
 foreach (var child in query1)
 {
 foreach (var atr in child.Attributes())
 {
 if (atr.Name.LocalName == "name" && atr.Value==connStringName)
 if (atr.NextAttribute != null && atr.NextAttribute.Name == "connectionString")
 atr.NextAttribute.Value = newValue;
 }
 }

 doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

 return true;
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 return false;
 }
}

Change connection string for Entity Framework at run-time

As you already know the connection string for Entity Framework is little bit different than the connection string used by DataSet and Lin2SQL. In order to modify the Entity framework connection string the previous code must be modified. The following code modified the entity framework connection string.

private bool ChangeEFConnectionString(string connStringName, string newValue)
{
try
{
//CreateXDocument and load configuration file
XDocument doc = XDocument.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

//Find all connection strings
var query1 = from p in doc.Descendants("connectionStrings").Descendants()
select p;

//Go through each connection string elements find atribute specified by argument and replace its value with newVAlue
foreach (var child in query1)
{
foreach (var atr in child.Attributes())
{
if (atr.Name.LocalName == "name" && atr.Value == connStringName)
if (atr.NextAttribute != null && atr.NextAttribute.Name == "connectionString")
{
// Create the EF connection string from existing
EntityConnectionStringBuilder entityBuilder =
new EntityConnectionStringBuilder(atr.NextAttribute.Value);
//
entityBuilder.ProviderConnectionString= newValue;
//back the modified connection string to the configuration file
atr.NextAttribute.Value = entityBuilder.ToString();
}
}
}

doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}

In the previous code we used the EntityConnectionStringBuilder which is very handy in this situation.

The source code for this post you can find on SkyDrive.

Advertisements

WPF i LINQ to SQL III dio, data validation


U prethodnom postu vidjeli smo na koji način možemo manipulirati podacima u smislu sortiranja, grupiranja, te filtriranja podataka. Za ovaj put prezentiraćemo validiranje podataka u WPF odnosno DataValidation. U WPF postoji predefinisan model validiranja podataka tako da svaki tip izveden iz IDataErrorInfo interfejsa podržava validiranje podataka.

Implementacija validacije podataka

Početak ovog posta baziran je na prethodnom primjeru, a potrebno je implementirari validiranje podataka za naš model podataka. Valdaciju podataka moguće je implementirati na različitim konceptialnim modelima aplikacije. U ovom poglavlju validaciju ćemo implementirati na nivou našeg modela baze podataka. Validacija će se sastojati u tome da kad god unesemo datum veći od 1. Januara 2009 godine u datum narudžbe informacija o nepravilnom unosu upozoravaće nas prilikom svakog gubljenja fokusa date kontrole na našem interfejsu. Obzirom da smo validaciju pretpostavili na nivou modela, potrebno je klasu Orders derivirati iz interfejsa IdataErrorInfo da bi iskoristili ugrađeni mehanizam u WPF.

Otvorimo datoteku NorthWindKlase.cs te definišimo parcijanu deklaraciju klase Orders na sljedeći način:

partial class Order : IDataErrorInfo
{
#region IDataErrorInfo Members
 public string Error
  {
   get { return null; }
  }
 public string this[string columnName]
  {
   get
    {
      if (columnName == "OrderDate")
         if (OrderDate > newDateTime(2009, 1, 1))
           return "Datum nije validan. Molimo ispravite datum.";
    return null;
   }
  }
#endregion
}

Klasa Order izvedena je iz dva interfejsa koja su definisana u dizajnerskog datoteci. U cs datoteci ovu klasu izvodimo iz još jednog interfejsa IdataErrorInfo. Ovaj interfejs obezbjedjuje implementaciju validacije podataka u WPF. Dvije implementacije je potrebno izvršiti i to za Property Error koja u ovom slučaju nije potrebna, a inače služi kada upravljamo sa više pogrešaka koje se mogu pojaviti u klasi Orders. Druga metoda je indexer u kojem prvo provjeravamo da li je vrijednost indexera posmatrani naziv kolone OrderDate. Zatim tekuću vrijednost provjeravamo, i ako vrijednost ne zadovoljava naše definisane kriterije vraćamo neprazan string koji u biti sadržava poruku pogreške.

Napomena: Kada u polju datuma ne postoji nikakva vrijednost (prazan string) ili vrijednost koja ne predstavlja datum, validacija takvih podataka je već implementirana tako da se takvi podaci neposmatraju ovom implementacijom. Naša validacija OrderDate kolone se sastoji u tome da ako smo definsiali datum koji je veći od 1. Januara 2009 godine, izbacuje se pogrešaka. Kada smo implementirali logiku validacije podataka u bussiness layeru, logiku je potrebno povezati sa UI kontrolama, odnosno sa TextBox kontrolom koja prikazuje OrderDate. Kada želimo da povežemo validaciju sa bilo kojom UI kontrlom postavljamo Property ValidatesOnDataErrors=True. Sa ovim je cijela implementacija validacije podataka iz bussiness layer povezana sa UI kontrolom.

Kada u ovoj fazi implementacije pokrenemo naš primjer i kad u polje OrderDate unesemo datum koji je veći od datuma 1. Januar 2009 godine, mehanizam validacije podataka se pokreće i dobijamo sljedeći sliku.

image_020720093C88EA80

Sa slike vidimo da je tekstualna kontrola Order Date promjenila boju ivice na crvenu. Ovo je standardni šablon koji se koristi kada se pokrene mehanizam validacije. Medjutim, sa crvenom bojom ivice mi ništa više ne znamo od pogreške. Za ovaj primjer implementirat ćemo šablon koji će tekst pogreške koji je uhvaćen u bussiness layeru prikazati kao tooltip naše kontrole. Da bi ovo implementirali potrebmo je definisati Stil validacije podataka. Stil validacije podataka definišemo na sljedeći način:

<!--Šablon validacije podataka-->
<Style  TargetType="TextBox">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip"
                    Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                    Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>
    </Style.Triggers>
</Style>

U biti gornja implementacija je implementacija stila za TextBox kontrolu koja u sebi sadrži implementaciju Triger (okidača) kad postoji pogreška u validaciji podataka. Kada se desi tada vrijednost ToolTipa date kontrole ima vrijednost teksta pogreške.

Sada kad pokrenemo aplikaciju te unesemo pogrešan datum kao u prethodnom primjeru, te odnesemo miša do date kontrole, pojavljuje se tooltip sa tekstom pogreške.

clip_02072009image002_6B0ECD95

Kada smo definisali Stil za validaciju podataka za textbox kontrolu nismo ga definisali sa ključnom nazivom (x:Key=”stilValidacije), što onda znači da dati stil automatski podešava sve textbox kontrole.

Sa ovim smo završili tutorijal o validaciji podataka.Izvorni kod za ovaj primjer možete skinuti sa ovog linka.

WPF i LINQ to SQL II dio- grouping, filtering, sorting


U prethodnom postu smo vidjeli jedan od načina povezivanja WPF aplikacije sa bazom podataka preko LINQ to SQL. Naše putovanje ide dalje, a ovaj put obradićemo grupiranje, filtriranje i sortiranje. Tutorijal startamo tamo gdje smo stali u prethodnom postu.

Grupiranje podataka

Za razliku od WindowsFormsa u WPF je moguće na vrlo jednostavan način implementirati grupiranje podataka u listbox kontroli. Obzirom da naša listbox kontrola prikazuje samo jednu stavku potrebno ju je kastomizirati. Da bi prikazali više stavki (više kolona i tabele) u listbox kontroli potrebno je implementirati šablon podataka odnosno DataTemplate. Data template nije ništa drugo nego struktura u kojoj je definisano kako treba da izgleda pojedinačna stavka u listi. Kako bi implementirali grupiranje potrebno je, takodjer definisati šablon grupiranja podataka.

U listbox kontroli definisaćemo DataTemplate koji će prikazati DateOrder i ShipPostalCode, a grupiranje ćemo definisati po DateOrder. DataTemplate prikazan je na sljedećoj slici:

<DataTemplate x:Key="sablonPodataka">
    <StackPanel Orientation="Vertical">
        <TextBlock Text="{Binding Path=OrderDate}"/>
        <TextBlock Text="{Binding Path=ShipPostalCode}"/>
    </StackPanel>
</DataTemplate>

Gornji listing prikazuje StackPanel u kojem se vertikalno poravnavaju dvije tektualne kontrole koje su povezane sa kolonama OrderDate i ShipPostalCode.

DataTemplate grupirane liste definisan je sljedećim DataTemplateom

<DataTemplate x:Key="sablonGrupiranihPodataka">
    <StackPanel Orientation="Vertical">
        <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Foreground="Red"/>
    </StackPanel>
</DataTemplate>

Ovdje je nešto drugačija situacija. Zaglavlje grupiranja sastoji se samo od jedne tekstualne kontrole ali ova kontrola je povezana sa nazivom osobine (PropertyName) objekta PropertyGroupDescription klase. Ova dva šablona definisali smo u resursu Windowsa, da bi bili dostupni u kontrolama koje su definisane. Definisane šablone potrebno je još povezati sa listbox kontrolom. Obzirom da listbox kontrola po defaultu prikazuje samo jednu stavku i to onu koja je definisana preko DisplayMemberPath osobine, potrebno je ovu osobinu zamjeniti sa novom ItemTemplate koja ima referencu na DataTemplate koji smo definisali na samom početku.

Pored toga, listbox kontroli potrebo je definisati Stil grupiranja koji će imati referencu na drugi šablon kojeg smo formirali. Sve rečeno prikazano je na listingu:

<ListBox Name="listBox1" Grid.RowSpan="6" Grid.Row="3"
         IsSynchronizedWithCurrentItem="True"
         ItemsSource="{Binding Source={StaticResource listaNarudzbi}}"
         ItemTemplate="{StaticResource sablonPodataka}" Grid.ColumnSpan="2">
    <ListBox.GroupStyle>
        <GroupStyle HeaderTemplate="{StaticResource sablonGrupiranihPodataka}" />
    </ListBox.GroupStyle>
</ListBox>

Kada smo definisali prethodne korake naša aplikacija je spremna za grupiranje podataka. Sada je još potrebno implementirati logiku odnosno opciju za grupiranje podataka. U tom smislu definisaćemo Checkbox dugme kojim ćemo grupirati odnosno degrupirati podatke u listbox kontroli. CheckBox dugme postavićemo kao na slici dolje, te mu implementirati dogadjaje Checked i UnChecked .

image

Implementacija dogadjaja sastoji se u formiranju PropertyGroupDescription objekta i postavljanjem Naziva grupirane kolone OrderDate. Zatim novoformirani objekat pridodajemo u kolekciju grupiranja koja je definisana u defaultView objektu.

Kada želimo grupiranje ukloniti potrebno je iz kolekcije izbaciti objekt za grupiranje. Implementacija se nalazi na sljedećem listingu.

//Grupiranje podataka
private void button3_Checked(object sender, RoutedEventArgs e)
{
    PropertyGroupDescription groupDesc = new PropertyGroupDescription("OrderDate");
    defaultView.GroupDescriptions.Add(groupDesc);
}
//De grupiranje podataka
private void button3_Unchecked(object sender, RoutedEventArgs e)
{
    defaultView.GroupDescriptions.Clear();
}

Pokrenimo aplikaciju te isprobajmo kako grupiranje radi.

Filtriranje podataka

Sljedeća implementacija sastoji se u filtriranju podataka. Filtriranje podataka postižemo definišući osobinu (Property) Filter objekta defaultView. Za ovu implementaciju definisaćemo edit kontrolu koja će filtrirati narudžbe po poštanskom broju (ShiPostalCode). Prilikom kucanja poštanskog broja stavke u listbox kontroli će se filtrirati na osnovu unešenog broja. Edit kontrola prikazana ja na sljedećoj slici:

image

Implementacija filtriranja stavki po poštanskom broju prikazan je na sljedećem listingu:

//Filtriranje podataka u listi
private void textBox6_TextChanged(object sender, TextChangedEventArgs e)
{
    string text = this.textBox6.Text.ToLowerInvariant();
    if (defaultView.CanFilter)
        defaultView.Filter = delegate(object obj)
        {
            Order narudzba = obj as Order;

            if (narudzba != null && narudzba.ShipPostalCode != null)
                return narudzba.ShipPostalCode.ToLowerInvariant().Contains(text);
            return false;
        };
}

Filter smo definisanli delagatom koji za parametar uzima narudžbu iz liste, te provjerava da li sadrži definisani text, te vraća true ako postoji traženi text, inače vraća false.

Sortiranje podataka

Slično kao i kod grupiranja sortiranje definišemo preko objekta ListCollectionView podešavanje propertya SortDescriptions. Sljedeći listing prikazuje sortiranje po datumu te u drugoj metodi uklanjamo sortiranje definisano prethodno.

//Sortiranje po datumu
private void checkBox1_Checked(object sender, RoutedEventArgs e)
{
   SortDescription sortiranjePoDatumu=new SortDescription("OrderDate",ListSortDirection.Ascending);
   defaultView.SortDescriptions.Add(sortiranjePoDatumu);
}
//Resetovanje sortiranje na početno
private void checkBox1_Unchecked(object sender, RoutedEventArgs e)
{
    defaultView.SortDescriptions.Clear();
}

Na sljedećoj slici prikazan je checkbox preko kojeg definišemo sortiranje podataka, Kada otkačimo checkbox sortiranje se resetuje.

image

Ovim smo završili našu implementcaiju grupiranja i sortiranja podatka. Izvorni kod za ovaj primjer dat je na ovom linku.

WPF i LINQ to SQL


U narednih nekoliko postova biće riječi o novoj microsoftovoj tehnologiji za razvoj windows aplikacija Windows Presentation Foundation, kao i razvoj aplikacija koje se oslanjaju na baze podataka preko LINQ to SQL i LINQ to Entity. Biće prikazani osnovni modeli aplikacije sa prikazom implementacije osnovnih CRUD operacija razvijani na WPF tehologiji.

Kratki uvod

WPF je nova tehnologija razvoja windows aplikacija bazira na DirectX grafičkoj biblioteci, umjesto klasičnih GDI aplikacija na kojim su se zasnivale sve dosadašnje microsoftove tehnologije. Ovim prelazom omogućen je razvoj windows grafičkih interfejsa na sličan način kako se to radi sa web aplikacijama. U tom smislu razvijen je novi programski jezik XAML (čitaj zaml) koji je sastavni dio .NET Frameworka. Sa razvojem XAML razvijen je novi skup programskih rješenja koja pomažu u dizajnu windows aplikacija nazvan Expression Studio. Ovaj paket aplikacija uključuje Expression Blend, Expresion Design i druge aplikacije kojim razvijamo GUI dok logiku ispod kontrola GUI-a razvijamo u klasičnim razvojnim alatima poput Visual Studia. Sa ovim se razdvojio dizaj i logika aplikacije te uvela nova tehnologija razvoja aplikacija kao i sistematičnija kolaboracija izmedju dizajnera i developera.

Informacije o WPF mogu se pronaći na internetu sa vrlo različitim novoima predznanja, te u ovom vrlo kratkom uvodu želio sam samo natuknuti neke od osnovnih značajki ove tehnologije. Svakako prije čitanja ovih postova potrebno je minimalno predznanje o WPF tehnologiji. Prvi post će biti prikazan u obliku tutorijala s kojim ćemo implementirati jednostavan primjer povezivanja baze podataka sa WPF aplikacijom, te upoznati osnovne operacije umetanja, modifikacije i brisanja zapisa iz baze podataka. Primjer će također prikazati neke od metoda na koji način koristimo Visual Studio 2008 i Microsoft Expression Blend u razvoju aplikcija. Za ovaj i primjere koji će biti prikazani u narednim postovima, potrebna je instalacija Visual Studio 2008 SP1, Expresion Blend 2, Microsoft SQL Server 2005 ili 2008,NorthWind baza podataka, a svi se oni mogu skinuti na microsoftovim stranicama, kao i u besplatin express verzijama.

NorthWind WPF primjer

Prije početka potrebno je NorthWind bazu podataka instalirati na server, kako bi se kroz Visual studio mogao formirati model baze podataka.

Pokrenimo VS 2008 te formirajmo novi WPF projekat kao na sljedećoj slici.

Nakon formiranja WPF projekta potrebno je formirati LINtoSQL model northwind baze podataka. Način na koji formiramo model možete pogledati na jednom od mojih prethodnih blog postova. Ovaj put naš model se sastoji od sljedećih tabela baze podataka: Customer, Employee, Order, Order_Detail. Sada naš projekat izgleda kao na slici 2.

U solucijskog exploreru možemo vidjeti da se naš projekat sastoji od Window1.xaml i korespodentne cs datoteke, App.xaml te korespodentne cs datoteke, kao i novoformiranog modela baze podataka kojeg smo objašnjavali u prethodnim postovima. Da bi NorthWind model baze podataka inkorporirali sa aplikacijom potrebno je dodatno implementirati logiku.

Kada sa prethodne slike desnim klikom miša odaberemo opciju View Code dobijamo implementaciju klase NorthWindKlaseDataContext. U klasi je potrebno implementirati metode za izvlačenje svih Narudžbi (Odrers), Dobavljača i Zaposlenika. Implementacija je prikazana u sljedećoj slici:

namespace NorthWindWPFPrimjer
{
    using System.Collections.ObjectModel;
    using System.Linq;

    partial class NorthWindKlaseDataContext
    {
        public ObservableCollection<Order> IzvuciNarudze()
        {
            var query = from p in Orders select p;
            return new ObservableCollection<Order>(query);
        }
        public ObservableCollection<Customer> IzvuciDobavljace()
        {
            var query = from p in this.Customers select p;
            return new ObservableCollection<Customer>(query);
        }
        public ObservableCollection<Employee> IzvuciZaposenike()
        {
            var query = from p in this.Employees select p;
            return new ObservableCollection<Employee>(query);
        }
    }
}

Važna napomena: Nemojte ni u kom slučaju using naredbe postavljati iznad prostora imena NorthWindWPFPrimjer jer će vam se izgubiti datoteka dizajnera i vaš model će nestati. Nažalost ovo je bug koji se nalazi u Visual Studio 2008 SP1.

Na ovaj način implementirali smo metode za izvlačenja podataka iz baze podataka. Sada je na redu da to implementiramo u window1.xaml datoteci. Da bi prikazali podatke o naružbama u window1.xaml datoteci potrebno je formirati objekat ObjectDataProvider kojim ćemo povezati kontrole za prikaz narudžbi. Naravno, ovaj tutorijal neće ulaziti u detalje i objašnjenja svih pojmova i tipova podataka, jer to i nije svrha. Možemo kazati da ObjectDataProvider obuhvata i formira objekat koji omogućuje povezivanje sa izvorom podataka. U WPF izvor podataka mogu biti klasični izvori podataka: vanjska baza podataka, XML datoteka, in memory kolekcija podataka, kao i svaka windowsova standardna ili kastomizirana kontrola, odnosno bilo koji .NET objekat. Ovo je i jedan od najvažnijih aspekata ove tehnologije. Kako smo na samom početku rekli XAML kao novi prograski jezik nije zamjena za klasične .NET jezike, on u biti predstavlja jedno proširenje .NET programskim jezicima, tako da sve što se može implementirati pomoću XAML-a možemo to učiniti i sa C# odnosno VB jezikom, dok obrnuto ne vrijedi.

Prilikom razvijanja aplikacije u WPF, implementacija u XAML datoteci označava deklarativnu implementaciju dok se implementacija u korespondentnom C# ili VB jeziku zove code-behind implementacija.

Dizaj aplikacije

Sada je potrebno našu aplikaciju dizajnirati, u principu potrebno je definisati kontrole koje će kasnije biti povezane sa bazom podataka odnosno sa tabelama i kolonama. Dizaj aplikacije sastoji se od jedne ListBox kontrole u kojoj će biti prikazane sve narudžbe, dok će sa desne strane biti polja u kojim će biti prikazani detalji svake narudžbe pojedinačno. Donja slika prikazuje dizaj prozora.

Sa desne strane postavili smo detalje svake narudžbe od kojih je najinteresantniji dio kolone Customer i Employee koji predstavljeju vanjske ključeve za tabele Customer i Employee. Preko ComboBoxa ostvarićemo ovu relaciju, gdje ćemo u combobox listi prikazati sve partnere (Customers) i zaposlenike (Employees). Obzirom da u standardnom setu kontrola ne postoji kontrola izbora Datuma i Vremena koristimo običnu edit kontrolu Text Box za prikaz datuma.

Cjelokupan dizajn gornjeg prozora uradili smo u XAML datoteci dok ćemo logiku aplikacije implementirati u cs datoteci ili tzv. Code-behind datoteci. Ovo je klasičan primjer upotrebe WPF tehnologije. Dizaj aplikacije implementirati u XAML, a logiku u code-behind datoteci.

Povezivanje sa bazom podataka

Da bi povezali aplikaciju sa bazom podataka potrebno je formirati objekat klase NorthWindKlaseDataContext preko kojeg ćemo vršiti upit prema bazi podataka. Ovdje ćemo pokazati dva načina implementacije. Jedan način je da u code-behind formiramo objekat te povežemo kontrole sa izvorom podataka, a drugi da u XAML-u uradimo isto. Oba načina su ispravna i nema nikave razlike u pogledu performansi. Na sljedećem ispisu prikazan je code-behind način. Listing datoteke Window1.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace NorthWindWPFPrimjer
{
    public partial class Window1 : Window
    {
        NorthWindKlaseDataContext dx = new NorthWindKlaseDataContext();
        public Window1()
        {
            InitializeComponent();

            listBox1.ItemsSource = dx.IzvuciNarudze();
            listBox1.DisplayMemberPath = "OrderID";

            Binding binding = new Binding();
            binding.Source = listBox1.ItemsSource;
             //OrderID
            binding.Path = new PropertyPath("OrderID");
            textBox1.SetBinding(TextBox.TextProperty, binding);

            //OrderID
            Binding binding1 = new Binding();
            binding1.Source = listBox1.ItemsSource;
            binding1.Path = new PropertyPath("CustomerID");
            comboBox1.ItemsSource = dx.IzvuciDobavljace();
            comboBox1.DisplayMemberPath = "ContactName";
            comboBox1.SelectedValuePath="CustomerID";
            comboBox1.SetBinding(ComboBox.SelectedValueProperty, binding1);

            //EmployeeID
            Binding binding2 = new Binding();
            binding2.Source = listBox1.ItemsSource;
            comboBox2.ItemsSource = dx.IzvuciZaposenike();
            comboBox2.DisplayMemberPath = "FirstName";
            comboBox2.SelectedValuePath = "EmployeeID";
            binding2.Path = new PropertyPath("EmployeeID");
            comboBox2.SetBinding(ComboBox.SelectedValueProperty, binding2);

            Binding binding3 = new Binding();
            binding3.Source = listBox1.ItemsSource;
            //OrderDate
            binding3.Path = new PropertyPath("OrderDate");
            textBox2.SetBinding(TextBox.TextProperty, binding3);

            Binding binding4 = new Binding();
            binding4.Source = listBox1.ItemsSource;
            //ShipVia
            binding4.Path = new PropertyPath("ShipVia");
            textBox3.SetBinding(TextBox.TextProperty, binding4);

            Binding binding5 = new Binding();
            binding5.Source = listBox1.ItemsSource;
            //Freight
            binding5.Path = new PropertyPath("Freight");
            textBox4.SetBinding(TextBox.TextProperty, binding5);

            Binding binding6 = new Binding();
            binding6.Source = listBox1.ItemsSource;
            //ShipPostalCode
            binding6.Path = new PropertyPath("ShipPostalCode");
            textBox5.SetBinding(TextBox.TextProperty, binding6);
        }
    }
}

Pokrenimo aplikaciju iz VS i dobićemo sljedeću sliku:

Ako pokušamo da selektujemo drugu stavku iz liste automatski cemo dobti druge vrijednosti u desnim kontrolama. Ovo automatsko sihroniziranje selektovane stavke iz liste i kontrola obezbjedjeno je formiranjem ObservableCollection klase te osobine liste IsSynchronizedWithCurrentItem=”True”.

Sljedeći listing prikazuje prethodno ali implementirano u XAML-u.

<Window x:Class="NorthWindWPFPrimjer.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:NorthWindWPFPrimjer"
    Title="NorthWind Prijmer" Height="357" Width="514" Closing="Window_Closing">
    <Window.Resources>
        <!--Formiranje ObjectDataProvidera preko NazivaMetode bez parametara-->
        <ObjectDataProvider x:Key="listaNarudzbi"
                            ObjectType="{x:Type local:NorthWindKlaseDataContext}" MethodName="IzvuciNarudzbe"/>
        <ObjectDataProvider x:Key="listaPartnera"
                            ObjectType="{x:Type local:NorthWindKlaseDataContext}" MethodName="IzvuciDobavljace"/>
        <ObjectDataProvider x:Key="listaZaposlenika"
                            ObjectType="{x:Type local:NorthWindKlaseDataContext}" MethodName="IzvuciZaposenike"/>
    </Window.Resources>
    <Grid>
        <!--Rešetka za raspored kontrola-->
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="150" />
        </Grid.ColumnDefinitions>
        <!--List box kontrola za naslovom-->
        <TextBlock Margin="0,0,0,0" Name="textBlock1" Text="Lista Naružbi"
                   VerticalAlignment="Center" HorizontalAlignment="Center"
                   FontSize="16" FontWeight="Bold" Foreground="Chocolate" />
        <ListBox Name="listBox1" Grid.RowSpan="7" Grid.Row="1" IsSynchronizedWithCurrentItem="True"
                 ItemsSource="{Binding Source={StaticResource listaNarudzbi}}" DisplayMemberPath="OrderID" />

        <!--Labele za oznakama polja za editovanje-->
        <Label Grid.Column="1" Margin="10,12,0,0" Name="label1" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">OrderID:</Label>
        <Label Margin="6,6,4,6" Name="label2" Grid.Column="1" Grid.Row="1" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Customer:</Label>
        <Label Margin="6,12,4,0" Name="label3" Grid.Column="1" Grid.Row="2" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Employee:</Label>
        <Label Margin="6,6,4,6" Name="label4" Grid.Column="1" Grid.Row="3" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Order Date:</Label>
        <Label Margin="6,6,4,6" Name="label5" Grid.Column="1" Grid.Row="4" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Ship Via:</Label>
        <Label Margin="6,6,4,6" Name="label6" Grid.Column="1" Grid.Row="5" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Freight:</Label>
        <Label Margin="6,12,4,0" Name="label7" Grid.Column="1" Grid.Row="6" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Postal Code:</Label>
        <!--Kontrole za modifikaciju i prikaz kolona narudžbe-->
        <TextBox Margin="0,8,0,8" Grid.Column="2" Grid.Row="0" Name="textBox1"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=OrderID}" />
        <ComboBox Margin="0,8,0,8" Grid.Column="2" Grid.Row="1"  Name="comboBox1"
                  ItemsSource="{Binding Source={StaticResource listaPartnera}}"
                  SelectedValuePath="CustomerID"
                  SelectedValue="{Binding Source={StaticResource listaNarudzbi}, Path=CustomerID}"
                  DisplayMemberPath="ContactName"/>
        <ComboBox Margin="0,8,0,8" Name="comboBox2" Grid.Column="2" Grid.Row="2"
                  ItemsSource="{Binding Source={StaticResource listaZaposlenika}}"
                  SelectedValuePath="EmployeeID" SelectedValue="{Binding Source={StaticResource listaNarudzbi},  Path=EmployeeID}"
                  DisplayMemberPath="FirstName"/>
        <TextBox Margin="0,8,0,8" Name="textBox2" Grid.Column="2" Grid.Row="3"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=OrderDate }" />
        <TextBox Margin="0,8,0,8" Name="textBox3" Grid.Column="2" Grid.Row="4"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=ShipVia}" />
        <TextBox Margin="0,8,0,8" Name="textBox4" Grid.Column="2" Grid.Row="5"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=Freight}" />
        <TextBox Margin="0,8,0,8" Name="textBox5" Grid.Column="2" Grid.Row="6"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=ShipPostalCode}" />
        <!--Dugmad za brisanje i dodavanje stavki u bazu podataka-->
        <Button Grid.Column="2" Grid.Row="7" Margin="65,6,23,10" Name="button1">Obriši</Button>
        <Button Margin="21,6,17,10" Name="button2" Grid.Column="1" Grid.Row="7" Click="button2_Click">Nova</Button>
    </Grid>
</Window>

Podcrtani XAML kod označava novi kod koji smo dodali pri povezivanju kontrola sa bazom podataka.

Na samom početku definisali smo ObjectDataProvide preko NazivaMetode, i to za svaku tabelu. ObjectDataProvider uvijek se definiše unutar resursa Kontrole roditelja te na taj način objekt postaje vidljiv u svim kontrolama koje pripadaju datom roditelju.

Definisanje logike aplikacije

Prethodno smo definisali model baze podataka preko LINQtoSQL dizajnera, dodatno implementirali poslovnu logiku modela. Zatim smo dizajnirali našu aplikaciju na način da smo definisali raspored i vrste kontrola. Poslije toga povezali smo bazu podataka sa aplikacijom i prikazali podatke preko kontrola.

Za ovaj tutorijal ostaje da implementiramo CRUD operacije odnosno modifikaciju podataka, brisanje i dodavanje redova u bazu podataka. Za početak implementirajmo modifikaciju podataka na način da kad se aplikacija zatvori, da se provjeri da li su podaci mijenjani u odnosu na originalne podatke i baze podataka te na osnovu toga izvršiti modifikaciju baze podataka.

Za ovo nam je potrebno implementirati Closing dogadjaj.

Implementacija unosa novog reda u tabeli

Da bi uopće manipulisali prikazanim podacima u našoj aplikaciji potrebno je dobiti referencu na ListCollectionView a koja predstavlja tekuće podatke u našoj aplikaciji. Takodjer ako smo povezivanje uradili u XAML-u potrebno je definisati referencu na objekat NorthWindKlaseDataContext, a koju ćemo dobiti iz ObjectDataProvidera.

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
 {
  //U koliko je u toku zatvaranja prozora jos uvijek postojala modifikacija odredjene stavke
  //potrebo napraviti Refresh da bi sve promjene bile aktualizirane
  defaultView.Refresh();

  //Provjera da li postoji bilo kakva promjena koja bi se trebala zapisati u bazu podataka
  int br = dataContext.GetChangeSet().Deletes.Count +
           dataContext.GetChangeSet().Inserts.Count +
           dataContext.GetChangeSet().Updates.Count;

  if (br > 0)
    {
      if (MessageBox.Show("Da li želite pohraniti nastale promjene?",
           "WPF Primjer", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
        {
            dataContext.SubmitChanges();
        }
    }
 }

Iz tog razloga potrebno je na novou Windows objekta formirati članove na sljedeći način:

//Referenca na DefaultView koja je definisan u list kontroli
ListCollectionView defaultView;
//Referenca da DataContext
NorthWindKlaseDataContext dataContext;

Prilikom učitavanja aplikacije odnosno pozivanja dogadjaja Loaded potrebno je ove reference definisati:

private void Window_Loaded(object sender, RoutedEventArgs e)
 {
   //Referenca na DefaultView
   defaultView = (ListCollectionView)CollectionViewSource.GetDefaultView(listBox1.ItemsSource);
   dataContext = (NorthWindKlaseDataContext)(FindResource("listaNarudzbi") as ObjectDataProvider).ObjectInstance;

    Debug.Assert(defaultView != null);
    Debug.Assert(dataContext != null);
 }

Dodavanje nove stavke vrši se jednostavno na sljedeći način:

//Dodavanje nove stavke
private void button2_Click(object sender, RoutedEventArgs e)
 {
   //dodavanje nove stavke
   Order newOrder = (Order)defaultView.AddNew();
   //novoformiranu stavku pohraniti u bazu podataka prvi put kada se pozove SubmitCange
   dataContext.Orders.InsertOnSubmit(newOrder);

 }

Pozivom AddNew metode iz defaltView i novu stavku potrebno je registrovati u DataContext da bi se pohranile promjene. Kada pokrenemo aplikaciju i kliknemo da dugme Dodaj, u listBox na kraju se pojavi nova stavka. Sa desne strane popunimo polja. Prilikom zatvaranja aplikacija pojavljuje se upit za pohranu podataka.

Implementacija brisanja stavke

Birisanje stavke iz liste vršimo listingom prikazanim na sljedećoj slici:

//Brisanje tekuce stavke
private void button1_Click(object sender, RoutedEventArgs e)
  {
    if (MessageBox.Show("Da li želite obrisati tekuću stavku?",
         "WPF Primjer", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
          return;
    //Prvo je potrebno objekat da se objekat oznaci obrisan u DataContext
    dataContext.Orders.DeleteOnSubmit((Order)defaultView.CurrentItem);
    //Označeni objekat brisemo iz DafaulView
    defaultView.Remove(defaultView.CurrentItem);

  }

Pokrenemo aplikaciju te klikom na dugme Obriši pojavljuje se poruka za potvrdu brisanja stavke.

Zaključak

Ovim jednostavnim primjerom prikazali smo jedan od načina implementacije LINQ to SQL u WPF. Sljedećim postovima obradićemo manipulaciju sa podacima u smislu sortiranja grupiranja podataka. Također u narednim postovima govorićemo o konvertorima, kastomizaciji listbox kontrole i sl.

Izvorni kod za ovaj primjer možete skinuti sa ovog linka.