
		<rss version="2.0">
			<channel>
			<ttl>5</ttl>
				<title>ppedv Blog</title>
				<link>http://blog.ppedv.de</link>
				<description>update by ppedv ***** Team Blog</description>
				<lastbuildDate>Fri, 01 May 2026 03:56:04 GMT</lastbuildDate>

				<image>
				    <url>http://blogs.ppedv.de/images/logo2.gif</url>
				    <title>ppedv Blog</title>
				    <link>http://www.ppedv.de</link>
				</image>
	
		<item>
			<title>[Bernhard Grojer] Silverlight: DataBinding zu WCF Service - Teil 2/2</title>
			<description>Im letzten Posting haben wir mithilfe von Silverlight und WCF Daten am Client verfügbar gemacht. Außerdem haben wir bereits deklaratives DataBinding verwendet in XAML. Nun wollen wir noch dafür sorgen, dass der Client Änderungen in den (Customer) Objekten mitprotokolliert und diese später mittels WCF wieder an den Server gesendet / gespeichert werden können. Da wir bereits Objekte gegen unser DataGrid gebunden haben werden die Änderungen auch zurück ins Objekt gespeichert (TWO-WAY DataBinding) Unsere CustomerDataSource Klasse muss nun nur noch geänderte “Kunden” mitprotokollieren. Dafür können wir den selben Ansatz verwenden, den auch Silverlight/WPF für die akt. des UI verwendet oder auch der LINQ DataContext dies macht. Wir hängen uns an das PropertyChanged Event (vom Interface INotifyPropertyChanged) und lassen uns Informieren sobald eine Änderung erfolgt:  Dictionary&lt;Customer, string&gt; _ChangedObjects = new Dictionary&lt;Customer, string&gt;();
        public void RegisterChangeTracking(Customer c)
        {
            c.PropertyChanged += (sender, e) =&gt; 
                { 
                    var cus = sender as Customer;
                    if (_ChangedObjects.ContainsKey(cus))
                        _ChangedObjects[cus] += ";" + e.PropertyName;
                    else
                        _ChangedObjects.Add(cus, e.PropertyName);
                };
        }
Bevor nun ein Objekt in die Observable&lt;T&gt; Liste wandert (und somit im UI dargestellt wird) wird es mithilfe von RegisterChangeTracking T o) registriert. Ändert sich nun ein Property in der Klasse wird ein Eintrag im _ChangedObjects Dictionary erstellt. 
private void LoadCustomers()
        {
            CustomerServiceClient client = new CustomerServiceClient();
            client.GetCustomersCompleted += (sender, e) =&gt;
            {
                foreach (var c in e.Result)
                {
                    _Customers.Add(c);
                    RegisterChangeTracking(c);
                }

            };
            client.GetCustomersAsync();
        }Nun müssen wir nur noch das Dictionary mit den geänderten Daten dem WCF Service übergeben. 
private void SaveCustomers()
        {
            CustomerServiceClient client = new CustomerServiceClient();
            client.SaveCustomersCompleted += (sender, e) =&gt;
            {
                var b = e.Result;
            };
            client.SaveCustomersAsync(_ChangedObjects);
        }

Die Methode SaveCustomer wird nun aus der Silverlight-Anwendung aufgerufen (ein Button im UI triggert folgenden Code):
private CustomerDataSource CustomerDataSource
        {
            get
            {
                return this.Resources["Customers"] as CustomerDataSource;
            }
        }

        private void ButtonSave_Click(object sender, RoutedEventArgs e)
        {
            CustomerDataSource.Save();
        }
Damit ist die Client-Seite abgeschlossen und wir müssen uns nun noch um das tatsächliche Speichern in der CustomerService Klasse kümmern. Hier möchten wir natürlich Datenbankabfragen minimieren und soviel wie möglich mit einem gang zur Datenbank ausführen. Außerdem sollen nur die Felder gespeichert werden, die tatsächlich geändert wurden:
public bool SaveCustomers(Dictionary&lt;Customer, string&gt; Customers)
        {
            using (var DB = new NorthwindDataContext())
            {
                var query = from c in DB.Customers
                            where Customers.Keys.Select(cus =&gt; cus.CustomerID).Contains(c.CustomerID)
                            select c;

                var lst = query.ToList();
                Type t = typeof(Customer);
                foreach (var kv in Customers)
                {
                    var oldCustomer = kv.Key;
                    var newCustomer = lst.Single(cus =&gt; cus.CustomerID == oldCustomer.CustomerID);

                    foreach (var s in kv.Value.Split(new char[] {&apos;;&apos;}, StringSplitOptions.RemoveEmptyEntries))
                    {
                        var propInfo = t.GetProperty(s);
                        var v = propInfo.GetValue(oldCustomer, null);
                        propInfo.SetValue(newCustomer, v,null);
                    }
                }

                DB.SubmitChanges();
            }
            return true;
        }
Das fertige Beispiel (selber Link wie im Teil 1 d. Blog-Serie) steht zum Download bereit: SilverlightConsumeWCF 08042009.zip</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/Silverlight-DataBinding-zu-WCF-Service---Teil-22</link>
			<author>Bernhard Grojer </author>
			<pubDate>Thu, 09 Apr 2009 08:43:56 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] Silverlight 3: NetworkChange (u. DataBinding mit INotifyPropertyChanged)</title>
			<description>In Silverlight 3 gibt es nun eine einfache Möglichkeit um den aktuellen Netzwerkstatus zu erkennen. Netzwerkstatus: Über die statische Methode NetworkInterface.GetIsNetworkAvailable() bekommt man nun die Information ob die Verbindung im Moment verfügbar ist oder nicht. Die Klasse NetworkChange stellt hingegen das Event NetworkAddressChanged bereit, das gefeuert wird sobald sich der Netzwerkstatus ändert. DataBinding: Über DataBinding können wir nun recht einfach die Funktionalität im UserInterface darstellen. Mithilfe von einem Binding von der Klasse zu einer CheckBox auf das Property IsChecked=”{Binding Path=IsOnline, Source={StaticResource State}}” kann nun in XAML an eine Ressource angebunden werden. (in dem Fall wird das Property IsOnline abgegriffen von der Resource mit dem Key State)  ; Somit haben wir im UserInterface (= unser Silverlight UserControl) 0 Zeilen Programmcode. Klasse: 	public class NetworkState : INotifyPropertyChanged
    {
        public NetworkState()
        {
            NetworkChange.NetworkAddressChanged +=
                   (sender, args) =&gt; SendNotifyPropertyChanged("IsOnline");
        }

        public void SendNotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public bool IsOnline
        {
            get
            {
                return NetworkInterface.GetIsNetworkAvailable(); ;
            }
        }
        
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
UserControl (XAML): 
&lt;UserControl x:Class="SilverlightNetworkState.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:SilverlightNetworkState"
    Width="400" Height="300"&gt;
    &lt;UserControl.Resources&gt;
        &lt;local:NetworkState x:Key="State" /&gt;
    &lt;/UserControl.Resources&gt;
    &lt;Grid x:Name="LayoutRoot" Background="White"&gt;
        &lt;CheckBox Margin="10" IsChecked="{Binding Path=IsOnline, Source={StaticResource State}}" Content="Online" /&gt;
    &lt;/Grid&gt;
&lt;/UserControl&gt;Download: SilverlightNetworkState 07042009.zip</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/Silverlight-3-NetworkChange-u.-DataBinding-mit-INotifyPropertyChanged</link>
			<author>Bernhard Grojer </author>
			<pubDate>Wed, 08 Apr 2009 08:46:07 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			Silverlight</category><category>
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] Silverlight: DataBinding zu WCF Service - Teil 1/2</title>
			<description>In Silverlight kann mittels DataBinding sehr einfach ein WCF-Service konsumiert werden.  ; Mit Hilfe von INotifyCollectionChanged und INotifyPropertyChanged bekommen wir im Bereich DataBinding ausgezeichnete Möglichkeiten Änderungen ins UI zu puplizieren. Im Beispiel habe ich die Customer Tabelle der Northwind-Datenbank gewählt und diese über ein WCF Service (BasicHttpBinding mit AspNetCompatibility) bereitgestellt. [ServiceContract]
    public interface ICustomerService
    {
        [OperationContract]
        List&lt;Customer&gt; GetCustomers();

        [OperationContract]
        bool SaveCustomers(Dictionary&lt;Customer, string&gt; Customers);
    }

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class CustomerService : ICustomerService
    {
        #region ICustomerService Members

        public List&lt;Customer&gt; GetCustomers()
        {
            using (var DB = new NorthwindDataContext())
            {
                var query = from c in DB.Customers
                            select c;
                return query.ToList();
            }
        }

        public bool SaveCustomers(Dictionary&lt;Customer, string&gt; Customers)
        {
            TODO: Implement Save
            return true;
        }

        #endregion
    }
Damit dieses Service verfügbar ist muss noch die passende web.config (Service Configuration Editor) erstellt werden (passende .svc Datei nicht vergessen bei WCF Service unter WAS/IIS)  Dieses Service wird in Silverlight von der Klasse CustomerDataSource asynchron konsumiert. Dies hat natürlich den Vorteil, dass das UI sofort verfügbar ist wärend die Daten noch nachgeladen werden. Und das man von der ersten Sekunde an deklaratives DataBinding benutzen kann.
Damit die Daten aber tatsächlich nachgeladen werden können brauchen wir zuerst einen Proxy den wir über “Add Service Reference” erzeugen lassen. (Meta-Daten müssen vom Service aktiviert/bereitgestellt werden).  
Sobald der CustomerServiceCleint (generierter Code) nun verfügbar ist können wir eine passende Klasse erzeugen und das Service benutzen.
public class CustomerDataSource
    {        
        public CustomerDataSource()
        {
            LoadCustomers();
        }

        private void LoadCustomers()
        {
            CustomerServiceClient client = new CustomerServiceClient();
            client.GetCustomersCompleted += (sender, e) =&gt;
            {
                foreach (var c in e.Result)
                {
                    _Customers.Add(c);
                }

            };
            client.GetCustomersAsync();
        }

        ObservableCollection&lt;Customer&gt; _Customers = new ObservableCollection&lt;Customer&gt;();
        public ObservableCollection&lt;Customer&gt; Customers
        {
            get {
                return _Customers;
            }

        }     
    }
Die Klasse stellt nun eine ObservableCollection&lt;T&gt; (Customers) bereit in Form eines Property. Gegen das wird in XAML deklarativ gebunden. Die Klasse CustomerDataSource beginnt beim Erzeugen das CustomerService aufzurufen. Sobald das Ergebnis vom Service da ist, wird die Liste _Customers befüllt. Da es sich hierbei um eine ObservableCollection&lt;T&gt; handelt und diese INotifyCollectionChanged implementiert wird das UI informiert sobald ein neuer Customer in die Liste wandert und DataGrid aktualisiert automatisch. In XAML fehlt und zuletzt noch das Binding:

&lt;UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="SilverlightConsumeWCF.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SilverlightConsumeWCF"&gt;
    &lt;UserControl.Resources&gt;
        &lt;local:CustomerDataSource x:Key="Customers" /&gt;
    &lt;/UserControl.Resources&gt;    
    &lt;Grid x:Name="LayoutRoot" Background="White"&gt;
        &lt;data:DataGrid ItemsSource="{Binding Path=Customers, Source={StaticResource Customers}}"&gt;
        &lt;/data:DataGrid&gt;
    &lt;/Grid&gt;
&lt;/UserControl&gt;Download: SilverlightConsumeWCF 08042009.zip Im Teil 2 wird noch editieren der Customer-Objekte ermöglicht. Das Service stellt die entsprechende Methodensignatur bereits bereit. </description>
			<link>http://blogs.ppedv.de/bernhardg/archive/Silverlight-DataBinding-zu-WCF-Service---Teil-12</link>
			<author>Bernhard Grojer </author>
			<pubDate>Wed, 08 Apr 2009 08:28:08 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] Visual Studio 2008, WPF, NVidia Treiber = (Designer)Problem</title>
			<description>   Unter Windows 7 scheint mit der aktuellen NVidia Notebook-Treibern (die off. NICHT für Windows 7 verfügbar sind) ein kleines&#160; merkwürdiges Problem mit VisualStudio 2008 u. WPF zu geben.        Zumindest auf meiner Box funktioniert danach im Visual Studio der “WPF Designer” nicht mehr. Nur mehr ein weißes “Fenster” und ein Visual Studio das mit 100% CPU Auslastung im endlos-loop läuft.     Die Anwendung (nachdem man sie via XAML reingehackt hat) läuft aber einwandfrei.        Mit den Windows7 Treibern für Nvidia Geforce Go (die man via Windows-Update bekommt) läufts soweit fein.</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/Visual-Studio-2008-WPF-NVidia-Treiber--DesignerProblem</link>
			<author>Bernhard Grojer </author>
			<pubDate>Thu, 12 Feb 2009 11:36:52 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			WPF</category><category>
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] ObjectDataSource in ASP.net (Keine Eintrge in der Auswahlliste mit Klassen f. Da</title>
			<description>   Gerade eben bin ich auf ein sehr merkwürdiges Problem gestossen.         In meiner Solution gab es keine Klassen in der Datenquellen-Auflistung.     Alles x-mal gecheckt und obwohl alle Referenzen verfügbar waren, die Klassen auch als public defeniert waren und alles wunderbar kompilierte klappt es nicht.         Keine Fehlermeldung,- einfach nichts :-(         Bei einem anderem Projekt probiert. Funktionierte einwandfrei.         Am Ende draufgekommen, dass es an meinem Ordnernamen gelegen ist: Scheinbar darf kein “#” in der Ordnerstruktur vorkommen.         Nummernzeichen weg und siehe da,- Es klappt.         Merke: Keinen Ordner C#Training mehr verwenden.</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/ObjectDataSource-in-ASP.net-Keine-Eintraumlge-in-der-ldquoAuswahllisterdquo-mit-Klassen-f.-Datenquel</link>
			<author>Bernhard Grojer </author>
			<pubDate>Thu, 12 Feb 2009 11:24:28 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] Generic Delegates: FuncT</title>
			<description>Im letzten Posting habe ich die Möglichkeiten beschrieben einen Delegate als Paramter zu akzeptieren.         Auch dort haben wir bereits den weg über Predicate&lt;T&gt; verwendet:              1: ... Demo1.GetDemos(  

       2:             delegate(Demo d)   

       3:                 {   

       4:                     return (d.Active &amp;&amp; d.Name == &quot;Test&quot;);

       5:                 }                  

       6:             );
  



  Oft ist man (wie im letzten Beispiel) nicht mehr gezwungen für alles einen eigenen Delegate zu erstellen. Hierfür kann man nun Func&lt;T&gt; (oder auch Action&lt;T&gt;, …) verwenden. 

  

  Aussehen kanns dann so:


  
       1: Func&lt;int, bool&gt; f = (i) =&gt; i == 1;

       2: var res = f(10);
  


Variable “f” beinhaltet nun unsere eigentliche Logik (Zuweisung über Lambda-Schreibweise). Dessen Aufruf ist dann denkbar einfach und natürlich können wir auch hier wieder Funktionen definieren die einen Parameter Func&lt;T&gt; nimmt. 
  </description>
			<link>http://blogs.ppedv.de/bernhardg/archive/Generic-Delegates-FuncltTgt</link>
			<author>Bernhard Grojer </author>
			<pubDate>Tue, 27 Jan 2009 15:05:26 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] PredicateT in C# 3.0</title>
			<description>   Funktionen/Methoden schreiben ist einfach. Paramter übergeben auch.         Schon mal eine Methode definiert die indirekt “Code” (einen Predicate&lt;T&gt;) als Parameter übernimmt?         Mithilfe eines Predicate&lt;T&gt; ermöglichen Sie die übergabe eines Delegates und schaffen somit die Möglichkeit Ihre eigene dynamischen (strongly Typed) Filter zu erstellen.         Wie kanns aussehen?         Zuerst die Funktion definieren die einen Predicate&lt;T&gt; als Paramter nimmt:             1: public static class Demo1   

       2: {   

       3:     public static List&lt;Demo&gt; GetDemos(Predicate&lt;Demo&gt; p)

       4:     {

       5:         var lst = GetList(); //Ladet eine Liste die gefiltert werden soll   

       6:         foreach (v i in lst) 

       7:         {

       8:             if (p(i))

       9:                 yield return i;

      10:         }

      11:     }

      12: }
  


Aufruf:


  
       1: var lst = Demo1.GetDemos(

       2:                 delegate(Demo d) 

       3:                     {

       4:                         return (d.Active &amp;&amp; d.Name == &quot;Test&quot;);

       5:                     }

       6:                );
  


Und somit sollten auch die Technolgien die hinter LINQ stecken wieder etwas verständlicher werden.</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/PredicateltTgt-in-C-3.0</link>
			<author>Bernhard Grojer </author>
			<pubDate>Mon, 26 Jan 2009 22:04:12 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] LINQ: Join</title>
			<description>In einem Linq Model kann man ein “Join” relativ einfach hinbekommen wenn die Einzelnen Elemente bereits Beziehungen haben. (Stichwort EntitySet&lt;T&gt;)        &#160;     Durch diese Beziehung kann man nun Abfragen (die mehr als ein Objekt/Tabelle betreffen) sehr einfach mit der . Schreibweise definieren.                      1: var query = from o in DB.Orders

       2:     select new

       3:     {

       4:         Name = o.Customer.CompanyName,

       5:         OrderID = o.OrderID

       6:     };
  


Doch oftmals gibts genau diese Beziehung zwischen den Objekten nicht (hier zwischen Customer u. Order). 
  Wie kommt man trotzdem zum Ergebnis? Join-Keyword! 

  


  
       1: var query = from o in DB.Orders

       2:     join c in DB.Customers on o.CustomerID equals c.CustomerID

       3:     select new

       4:     {

       5:         Name = c.CompanyName,

       6:         OrderID = o.OrderID

       7:     };
  


Download Sample: LinqJoin.zip</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/LINQ-Join</link>
			<author>Bernhard Grojer </author>
			<pubDate>Fri, 23 Jan 2009 11:44:03 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			.NET</category><category>C#</category><category>LINQ
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] LINQ Provider  Vom Ausdruck zum Ergebnis  Teil 4</title>
			<description>        Teil 4 der Blog-Serie zum Thema LINQ Provider.       Bevor Sie hier weiterleisen sollten sie die ersten 3 Teile gelesen haben.       Teil 1: Hintergründe und Ziele         Teil 2: Basisklasse Query&lt;T&gt;         Teil 3: Basisklasse QueryProvider   Da wir nun die Basisklassen soweit abgesteckt haben können wir nun dazu übergehen uns um die Implementierung zu kümmern.        Wir brauchen daher als ersten Punkt einen Provider (abgeleitet von QueryProvider) der unsere abstrakte Funktionalität Provider.Execute(…) implementiert.     Außerdem müssen wir noch eine Klasse erstellen, die unsere Daten (woher diese auch immer stammen) typsicher repräsentiert.         Für dieses Beispiel verwende ich nun eine Klasse “Employee” ….  public class Employee
{
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public bool Active { get; set; }
}


.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; }

… und den dazu passenden Provider …

public class EmployeeProvider : QueryProvider
{
        public override object Execute(Expression expression)
        {
             //Kommt noch …             return null;
        }
}


.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; }

Außerdem ist es noch “hilfreich”, wenn wir uns einen DataContext (sie kennen so etwas eventuell aus LINQ-TO-SQL) erzeugen:

public class NorthwindDataContext
{
        QueryProvider Provider = new EmployeeProvider();

        public Query&lt;Employee&gt; Employees
        {
            get { return new Query&lt;Employee&gt;(Provider); }
        }
}


.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; }

Und somit können wir nun unsere ersten Abfragen gegen unsere eigene Datenquelle erzeugen.

var context = new NorthwindDataContext();
var res = from e in context.Employees
          where e.Active
          orderby e.LastName
          select e;

Wenn Sie jetzt einen Breakpoint in die Provider.Execute Methode setzen und die Anwendung starten bekommen wir nun den von LINQ erzeugten ExpressionTree als Parameter in die Execute-Methode.

Diesen ExpressionTree gilt es nun noch auszuwerten, den gang zur Datenquelle zu machen und die Rückgabe zu erstellen. 
  

  Der von LINQ erstellte ExpressionTree enhält hierbei alle Information über die eigentliche Abfrage. Welche Felder inkludiert sind, welche Kritierien bei der Abfrage benötigt werden und auch welche Rückgabewerte erwartet werden. 

  

  Da – wie der Name schon sagt – der ExpressionTree eine Baumstruktur darstellt ist es oft notwendig eine Methode zu entwickeln die sich selbst aufruft und somit den kompletten Baum abarbeitet. Dabei wird eine Abfrage für die eigentliche Datenquelle erstellet. 

  

  In meinem Beispiel hab ich hierfür XML gewählt:

Die Execute(….) Methode bereitet einen LINQ Abfrage vor die wir entsprechend unseres ExpressionTrees in der ProcessExpression(….) Methode verändern/ersetzen.

public override object Execute(Expression expression)
{
      //Create query
      var doc = XDocument.Load(file);
      var query = from emp in doc.Descendants(&quot;Employee&quot;)
                  select emp;

      //Edit query
      ProcessExpression(expression, ref query);

      //Transform Data
      var res = GetElementsFromXml(query);

      //Return Data
      return res;
}


.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; }

In ProcessEpxression editieren wir nun die Linq To Xml Abfrage (natürlich könnte man hier auch einen SQL Abfrage zusammensetzen mit einem StringBuilder etc.) und haben am Ende die fertige Abfrage für die XML Datei. 
  

  ACHTUNG: Dies hier sollte lediglich einen Ansatz darstellen. In der Praxis wäre noch jede Menge zu tun. (mehere Bedinungen richtig verknüpfen, optimierungen f. d. Abfrage, implementieren aller Operatoren …)

private void ProcessExpression(Expression e, ref IEnumerable&lt;XElement&gt; resultQuery)
{
    if (e is UnaryExpression)
    {
        var exp = e as UnaryExpression;
        ProcessExpression(exp.Operand, ref resultQuery);
    }
    else if (e is LambdaExpression)
    {
        var exp = e as LambdaExpression;
        ProcessExpression(exp.Body, ref resultQuery);
    }
    else if (e is BinaryExpression)
    {
        var exp = e as BinaryExpression;
        if (exp.NodeType == ExpressionType.Equal)
        {
            string attrib = string.Empty;
            object value = null;

            if (exp.Left is MemberExpression)
            {
                var left = exp.Left as MemberExpression;
                attrib = left.Member.Name;
                value = Expression.Lambda(exp.Right).Compile().DynamicInvoke();
            }
            else if (exp.Right is MemberExpression)
            {
                var right = exp.Right as MemberExpression;
                attrib = right.Member.Name;
                value = Expression.Lambda(exp.Left).Compile().DynamicInvoke();
            }
            else
            {
                throw new NotImplementedException();
            }

            //ChangeTargetExpressionTree
            resultQuery = from emp in resultQuery
                          where emp.Attribute(attrib).Value == GetValueFromMapping(attrib, value).ToString()
                          select emp;
        }
    }
    else if (e is MethodCallExpression)
    {
        var exp = e as MethodCallExpression;
        string attrib, value = string.Empty;

        if (exp.Type == typeof(IOrderedQueryable&lt;Employee&gt;))
        {
            attrib = (((exp.Arguments[1] as UnaryExpression).Operand as LambdaExpression).Body as MemberExpression).Member.Name;
            resultQuery = from emp in resultQuery
                          orderby emp.Attribute(attrib).Value
                          select emp;
        }

        if (exp.Method.DeclaringType == typeof(string))
        {
            value = Expression.Lambda(exp.Arguments[0]).Compile().DynamicInvoke().ToString();
            attrib = (exp.Object as MemberExpression).Member.Name;

            switch (exp.Method.Name)
            {
                case &quot;Contains&quot;:
                    resultQuery = from emp in resultQuery
                                  where emp.Attribute(attrib).Value.Contains(value)
                                  select emp;
                    break;

                case &quot;StartsWith&quot;:
                    resultQuery = from emp in resultQuery
                                  where emp.Attribute(attrib).Value.StartsWith(value)
                                  select emp;
                    break;

                default:
                    throw new NotImplementedException();
            }
        }
        else
        {
            foreach (var current in exp.Arguments)
            {
                ProcessExpression(current, ref resultQuery);
            }
        }
    }
}


.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; }

Damit haben wir unseren ersten lauffähigen Provider und können die Anwendung testen. 
  

  Im 5ten und letzten Teil der Serie werden wir den Provider noch mit funktionalitäten ausstatten, um auch Änderungen speichern zu können (ChangeTracking).</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/LINQ-Provider-ndash-Vom-Ausdruck-zum-Ergebnis-ndash-Teil-4</link>
			<author>Bernhard Grojer </author>
			<pubDate>Fri, 17 Oct 2008 16:34:23 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] LINQ Provider  Vom Ausdruck zum Ergebnis  Teil 4</title>
			<description>        Teil 3 von der Blog-Serie zum Thema LINQ Provider.       Bevor Sie hier weiterleisen   sollten sie die ersten 3 Teile gelesen haben.      Teil 1: Hintergründe um Ziele         Teil 2: Basisklasse Query&lt;T&gt;         Teil 3: Basisklasse QueryProvider   Da wir nun die Basisklassen soweit abgesteckt haben können wir nun dazu übergehen uns um die Implementierung zu kümmern.        Wir brauchen daher als ersten Punkt einen Provider (abgeleitet von QueryProvider) der unsere abstrakte Funktionalität Provider.Execute(…) implementiert.     Außerdem müssen wir noch eine Klasse erstellen, die unsere Daten (woher diese auch immer stammen) typsicher repräsentiert.         Für dieses Beispiel verwende ich nun eine Klasse “Employee” ….  public class Employee
{
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public bool Active { get; set; }
}


.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; }

… und den dazu passenden Provider …

public class EmployeeProvider : QueryProvider
{
        public override object Execute(Expression expression)
        {
             //Kommt noch …             return null;
        }
}


.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; }

Außerdem ist es noch “hilfreich”, wenn wir uns einen DataContext (sie kennen so etwas eventuell aus LINQ-TO-SQL) erzeugen:

public class NorthwindDataContext
{
        QueryProvider Provider = new EmployeeProvider();

        public Query&lt;Employee&gt; Employees
        {
            get { return new Query&lt;Employee&gt;(Provider); }
        }
}


.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; }

Und somit können wir nun unsere ersten Abfragen gegen unsere eigene Datenquelle erzeugen.

var context = new NorthwindDataContext();
var res = from e in context.Employees
          where e.Active
          orderby e.LastName
          select e;

Wenn Sie jetzt einen Breakpoint in die Provider.Execute Methode setzen und die Anwendung starten bekommen wir nun den von LINQ erzeugten ExpressionTree als Parameter in die Execute-Methode.

Diesen ExpressionTree gilt es nun noch auszuwerten, den gang zur Datenquelle zu machen und die Rückgabe zu erstellen. 
  

  Der von LINQ erstellte ExpressionTree enhält hierbei alle Information über die eigentliche Abfrage. Welche Felder inkludiert sind, welche Kritierien bei der Abfrage benötigt werden und auch welche Rückgabewerte erwartet werden. 

  

  Da – wie der Name schon sagt – der ExpressionTree eine Baumstruktur darstellt ist es oft notwendig eine Methode zu entwickeln die sich selbst aufruft und somit den kompletten Baum abarbeitet. Dabei wird eine Abfrage für die eigentliche Datenquelle erstellet. 

  

  In meinem Beispiel hab ich hierfür XML gewählt:

Die Execute(….) Methode bereitet einen LINQ Abfrage vor die wir entsprechend unseres ExpressionTrees in der ProcessExpression(….) Methode verändern/ersetzen.

public override object Execute(Expression expression)
{
      //Create query
      var doc = XDocument.Load(file);
      var query = from emp in doc.Descendants(&quot;Employee&quot;)
                  select emp;

      //Edit query
      ProcessExpression(expression, ref query);

      //Transform Data
      var res = GetElementsFromXml(query);

      //Return Data
      return res;
}


.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; }

In ProcessEpxression editieren wir nun die Linq To Xml Abfrage (natürlich könnte man hier auch einen SQL Abfrage zusammensetzen mit einem StringBuilder etc.) und haben am Ende die fertige Abfrage für die XML Datei.&#160; 

  ACHTUNG: Dies hier sollte lediglich einen Ansatz darstellen. In der Praxis wäre noch jede Menge zu tun. (mehere Bedinungen richtig verknüpfen, optimierungen f. d. Abfrage, implementieren aller Operatoren …)

private void ProcessExpression(Expression e, ref IEnumerable&lt;XElement&gt; resultQuery)
{
    if (e is UnaryExpression)
    {
        var exp = e as UnaryExpression;
        ProcessExpression(exp.Operand, ref resultQuery);
    }
    else if (e is LambdaExpression)
    {
        var exp = e as LambdaExpression;
        ProcessExpression(exp.Body, ref resultQuery);
    }
    else if (e is BinaryExpression)
    {
        var exp = e as BinaryExpression;
        if (exp.NodeType == ExpressionType.Equal)
        {
            string attrib = string.Empty;
            object value = null;

            if (exp.Left is MemberExpression)
            {
                var left = exp.Left as MemberExpression;
                attrib = left.Member.Name;
                value = Expression.Lambda(exp.Right).Compile().DynamicInvoke();
            }
            else if (exp.Right is MemberExpression)
            {
                var right = exp.Right as MemberExpression;
                attrib = right.Member.Name;
                value = Expression.Lambda(exp.Left).Compile().DynamicInvoke();
            }
            else
            {
                throw new NotImplementedException();
            }

            //ChangeTargetExpressionTree
            resultQuery = from emp in resultQuery
                          where emp.Attribute(attrib).Value == GetValueFromMapping(attrib, value).ToString()
                          select emp;
        }
    }
    else if (e is MethodCallExpression)
    {
        var exp = e as MethodCallExpression;
        string attrib, value = string.Empty;

        if (exp.Type == typeof(IOrderedQueryable&lt;Employee&gt;))
        {
            attrib = (((exp.Arguments[1] as UnaryExpression).Operand as LambdaExpression).Body as MemberExpression).Member.Name;
            resultQuery = from emp in resultQuery
                          orderby emp.Attribute(attrib).Value
                          select emp;
        }

        if (exp.Method.DeclaringType == typeof(string))
        {
            value = Expression.Lambda(exp.Arguments[0]).Compile().DynamicInvoke().ToString();
            attrib = (exp.Object as MemberExpression).Member.Name;

            switch (exp.Method.Name)
            {
                case &quot;Contains&quot;:
                    resultQuery = from emp in resultQuery
                                  where emp.Attribute(attrib).Value.Contains(value)
                                  select emp;
                    break;

                case &quot;StartsWith&quot;:
                    resultQuery = from emp in resultQuery
                                  where emp.Attribute(attrib).Value.StartsWith(value)
                                  select emp;
                    break;

                default:
                    throw new NotImplementedException();
            }
        }
        else
        {
            foreach (var current in exp.Arguments)
            {
                ProcessExpression(current, ref resultQuery);
            }
        }
    }
}


.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; }

Damit haben wir unseren ersten lauffähigen Provider und können die Anwendung testen. 
  

  Im 5ten und letzten Teil der Serie werden wir den Provider noch mit funktionalitäten ausstatten, um auch Änderungen speichern zu können (ChangeTracking).</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/LINQ-Provider-ndash-Vom-Ausdruck-zum-Ergebnis-ndash-Teil-4</link>
			<author>Bernhard Grojer </author>
			<pubDate>Fri, 17 Oct 2008 16:13:44 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] LINQ Provider - Vom Ausdruck zum Ergebnis - Teil 3</title>
			<description>   Teil 3 von der Blog-Serie zum Thema LINQ Provider.      Bevor Sie hier weiterleisen sollten Teil 1 und Teil 2 gelesen haben.  Nachdem wir im Teil 2 unsere Query&lt;T&gt; Klasse implementiert haben stehen wir nun vor unserem letzten Problem: den eigentlichen Provider für die Datenquelle  Dieser muss:     - die Abfrage in möglichst optimierter Form f. d. Datenquelle entsprechend umwandeln      - das Ergebnis von der Datenquelle in die (Ziel-)Objekte wandeln und retournieren.   Genau dafür haben wir bereits vorab die Idee geboren eine entsprechende Provider-Basisklasse zu erstellen, um später nur noch die die eigentliche Logik - Provider.Execute(…) – umzusetzen zu müssen.  Daher implementieren wir im Provider die Funktionalität um eine Instanz von Query&lt;T&gt; zu bilden und diese zu retournieren (CreateQuery&lt;&gt;()).    Ein nicht generischer Aufruf ist hier im Moment nicht implementiert.  public abstract class QueryProvider : IQueryProvider
    {

        #region IQueryProvider Members

        public IQueryable&lt;T&gt; CreateQuery&lt;T&gt;(Expression expression)
        {
            return new Query&lt;T&gt;(this, expression);
        }

        public IQueryable CreateQuery(Expression expression)
        {
            throw new NotImplementedException();
        }

        T IQueryProvider.Execute&lt;T&gt;(Expression expression)
        {
            return (T)this.Execute(expression);
        }

        object IQueryProvider.Execute(Expression expression)
        {
            return this.Execute(expression);
        }

        #endregion

        public abstract object Execute(Expression expression);
    }


.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; }

In der Basisklasse erzeugen wir außerdem eine abstrakte Methode “Execute” die unser eigentlicher Provider später implementieren muss. 
  Die vom IQueryProvider Interface stammenden .Execute&lt;T&gt; Methoden rufen diese auf und reichen das Ergebnis weiter. 

  

  Somit haben wir bereits mehr als nur einen Grundstein gelegt und können nun verschiedene Provider on-top umsetzen und abfragen auf beliebige Datenquellen ermöglichen.

public class MyCustomProvider : QueryProvider
{
        public override object Execute(Expression expression)
        {
           //Execute Query, Create return Value(s)
        }
}


.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; }

Im vierten Teil der Serie werden wir uns eine Linq.Abfrage bereit legen und die Execute Methode in unsere konkrete Providerklasse implementieren. 
  

  Sie möchten mehr wissen zum Thema? Auf der ADC08 gibt es eine Session von mir: 

  </description>
			<link>http://blogs.ppedv.de/bernhardg/archive/LINQ-Provider---Vom-Ausdruck-zum-Ergebnis---Teil-3</link>
			<author>Bernhard Grojer </author>
			<pubDate>Fri, 10 Oct 2008 11:47:03 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] DataBinding in WPF/Silverlight  Refresh ohne Code im UI - INotifyPropertyChanged</title>
			<description>   Unter WPF und Silverlight ist DataBinding ein leichtes geworden. Wie funktionierts?         Mithilfe der Klasse (Binding) kann man sowohl im XAML Code als auch via Programmlogik ein DataBinding erstellen:     &lt;TextBlock Text=&quot;{Binding Path=MYPATH, Source=MYSOURCE&quot; /&gt;         MYPATH muss dabei ein Property sein, gegen das man binden möchte (zB die Value-Eigenschaft eines Sliders).     MYSOURCE hingegen ein Quelle (zB eine Instanz des Sliders)         Doch wir hätten diesmal gerne eine Uhrzeit im Userinterface (oder irgend einen anderen Wert aus der Programm-Logik).     Auch das ist in Silverlight/WPF kein Problem und umfasst 3 Schritte.         1) Unsere Datenquelle (Klasse) umsetzen und INotifyPropertyChanged implementieren     2) Eine Instanz der Klasse in den Ressourcen ablegen.     3) DataBinding zwischen der Resource und dem UI-Element erstellen         1) Die Klasse umsetzen:  public class RefreshingClock : INotifyPropertyChanged
    {
        DispatcherTimer dt;

        public RefreshingClock()
        {
            dt = new DispatcherTimer();
            dt.Interval = TimeSpan.FromSeconds(1);
            dt.Tick += dt_Tick;
            dt.Start();
        }

        void dt_Tick(object sender, EventArgs e)
        {
            if (this.PropertyChanged != null)            
                this.PropertyChanged(this, new PropertyChangedEventArgs(&quot;CurrentTime&quot;));
            
        }

        public DateTime CurrentTime
        {
            get
            {
                return DateTime.Now;
            }

        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }


.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; }

Hier ist eigentlich lediglich wichtig, dass wir immer, bei Änderungen d. Property “CurrentTime” unser INotifyPropertyChanged Event triggern müssen. 
  Siliverlight/WPF Bindings konsumieren hierbei dieses Event und werden Somit über die Änderung informiert. 

  

  2) Eine Instanz der Klasse bilden:

&lt;UserControl.Resources&gt;
        &lt;local:RefreshingClock x:Key=&quot;Clock&quot; /&gt;
&lt;/UserControl.Resources&gt;


.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; }

3) Das DataBinding: 

&lt;TextBlock Text=&quot;{Binding Path=CurrentTime, Source={StaticResource Clock}}&quot; /&gt;


.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; }

Und somit haben wir 0 Zeilen Programmcode im eigentlichen UI. 
  

  Das Ergebnis: 

  &#160; 

  Code zum Downloden gibt es hier.</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/DataBinding-in-WPFSilverlight-ndash-Refresh-ohne-Code-im-UI---INotifyPropertyChanged</link>
			<author>Bernhard Grojer </author>
			<pubDate>Thu, 09 Oct 2008 14:11:11 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] LINQ Provider - Vom Ausdruck zum Ergebnis - Teil 2</title>
			<description>   Teil 2 von der Blog-Serie zum Thema LINQ Provider.      Bevor Sie hier weiterleisen sollten Teil 1 gelesen haben.             Im ersten Teil haben wir bereits Basistechnologien abgesteckt und die Hintergründe schon etwas umschifft.     Wir sind weiteres dazu übergegangen uns mit 2 Basisklassen auseinanderzusetzen.         Auf der einen Seite haben wir uns dafür Query&lt;T&gt; bereit gestellt, die die eigentliche “Ergebnismenge” in Zukunft repräsentieren soll.     zB eine Liste von Kunden, Mitarbeitern, Produkten usw. usf.     Auf der anderen Seite hatten wir noch den QueryProvider, der den eigentlichen Gang zur Datenquelle, anhand der Basis-Interaces erstellt.  Zuerst beginnen wir nun die Funktionalitäten in Query&lt;T&gt; umzusetzen:        Hierfür wird es allerdings notwendig, dass wir eine Instanz unseres QueryProvider in dieser Klasse halten können und weiteres einen entsprechenden Konstrukter bereitstellen, der einen QueryProvider sowie optional einen ExpressionTree von LINQ entgegennimmt.     Wurde uns durch LINQ kein entsprechender ExpressionTree weitergegeben erzeugen wir uns eine ConstantExpression die unsere Ergebnismenge nicht weiter einschränkt.  public class Query&lt;T&gt; : IOrderedQueryable&lt;T&gt;, IQueryable, IOrderedQueryable
    {
        QueryProvider _Provider;
        Expression _Expression;

        public Query(QueryProvider provider)
        {
            this._Provider = provider;
            this._Expression = Expression.Constant(this);
        }

        public Query(QueryProvider provider, Expression expression)
            : this(provider)
        {
            this._Expression = expression;
        }

       //Implementierung der Interfaces ...
    }


.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; }

Bei der Implementierung des Interfaces machen wir nun nichts anderes als “jeweils” Provider.Execute(…) aufzurufen und diesen unsere Expression weitergereicht. 
  Die Auswertung und auch der Gang zur Datenquelle obliegt nun unserem Provider.

    public class Query&lt;T&gt; : IOrderedQueryable&lt;T&gt;, IQueryable, IOrderedQueryable
    {
       //...

        public IEnumerator&lt;T&gt; GetEnumerator()
        {
            var r = this.Provider.Execute&lt;IEnumerable&lt;T&gt;&gt;(this._Expression) as IEnumerable&lt;T&gt;;
            return r.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            var r = this.Provider.Execute(this._Expression) as IEnumerable;
            return r.GetEnumerator();
        }
  
       //...
     }

Und somit sind wir nun auch einem Geheimnis von LINQ auf die Schliche gekommen, weshalb Abfragen üblicherweise erst bei Zugriff ausgeführt werden. 
  Den Erst das Triggern von GetEnumerator() ruft die Execute Methode unseres Providers auf. 

  

  Unsere nächste Aufgabe wird somit ein Umsetzung unserer Provider-Basisklasse werden. Mehr dazu jedoch im 3ten Teil. 

  

  Sie möchten mehr wissen zum Thema? Auf der ADC08 gibt es eine Session von mir: 

  

  </description>
			<link>http://blogs.ppedv.de/bernhardg/archive/LINQ-Provider---Vom-Ausdruck-zum-Ergebnis---Teil-2</link>
			<author>Bernhard Grojer </author>
			<pubDate>Tue, 07 Oct 2008 11:03:15 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] ADO.net DataServices</title>
			<description>   Mit dem Release vom .net Framework 3.5 SP1 (böse Zungen sagen auch .net 3.6 dazu) haben wir eine relativ einfache Möglichkeit bekommen, um Daten über eine HTTP Schnittstelle bereitzustellen.         Was müssen wir dafür tun?       1) Erstellen einer neuen ASP.net Web Application     2) Ein ADO.net Entity Data Model erstellen (*.edmx)  3) Ein ADO.net Data Service hinzufügen und adaptieren.  Imports System.Data.Services
Imports System.Linq
Imports System.ServiceModel.Web

Public Class Northwind
    &apos; TODO: replace [[class name]] with your data class name
    Inherits DataService(Of NorthwindEntities)

    &apos; This method is called only once to initialize service-wide policies.
    Public Shared Sub InitializeService(ByVal config As IDataServiceConfiguration)
        &apos; TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
        &apos; Examples:
        &apos; config.SetEntitySetAccessRule(&quot;MyEntityset&quot;, EntitySetRights.AllRead)
        &apos; config.SetServiceOperationAccessRule(&quot;MyServiceOperation&quot;, ServiceOperationRights.All)

        config.SetEntitySetAccessRule(&quot;*&quot;, EntitySetRights.All)

    End Sub

End Class


.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; }

Achtung das ADO.net DataService muss hierbei vom Context abgeleitet werden.

4) Testen des Services. –&gt; F5 sollte hierfür reichen. 
  

  Im Firefox wirds sofort klappen. 

  Im Internet-Explorer (zumindest IE 8 Beta 2) vermutlich nicht. 

  http://127.0.0.1:49338/Northwind.svc/ &lt;- Im IE muss nämlich der letzte Schrägstrich noch manuell dran gemacht werden damits läuft.

 

Im einem zukünftigen Eintrag wollen wir das soeben erstellte Service noch konsumieren.

Fragen dazu? Kommentar posten ;)</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/ADO.net-DataServices</link>
			<author>Bernhard Grojer </author>
			<pubDate>Fri, 03 Oct 2008 21:14:00 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] LINQ Provider - Vom Ausdruck zum Ergebnis</title>
			<description>   SQL Server, Webservice, WCF, Dateisystem, CSV Dateien, XML, Logs, ...         ... &#252;berall Daten. Zugreifen? Mal so mal so. Immer andere Technologien erlernen um an die Daten ranzukommen.         Alternativen? Nat&#252;rlich!: LINQ Provider.         Was m&#252;ssen wir daf&#252;r tun? Eigentlich eine zentrale Stelle anfassen ...         &#160;  ... um zwischen der LINQ Engine und dem Datenspeicher unsere Logik implementieren. Doch leider ist die Aufgabe nicht ganz trivial und zwingt uns einige Tasks zu erledigen.        Daf&#252;r m&#252;ssen wir zuerst abstecken welche Aufgaben wir zu erledigen sowie welche Voraussetzungen wir habe:     API f&#252;r den Datenzugriff     Klasse f&#252;r Abfrage: IQueryable&lt;T&gt; (oder IOrderedQueryable&lt;T&gt;, dass IQueryable&lt;T&gt; implementiert)     Klasse f&#252;r den Provider: IQueryProvider     Datencontext erstellen der uns Strongly-Typed Zugriff auf die Datenquelle erlaubt.   Einen Teil der Funktionalit&#228;t k&#246;nnen wir in Basisklassen ablegen.     public class Query&lt;T&gt;: IOrderedQueryable&lt;T&gt;, IQueryable,IOrderedQueryable 
    {
        QueryProvider _Provider;
        Expression _Expression;
    }

public abstract class QueryProvider : IQueryProvider
    {
    }


.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; }

Query&lt;T&gt; bietet uns somit bereits eine generische Basis f&#252;r die weitere Implementierung unserer Datenquellen. 
  Die QueryProvider Basisklassen erlaubt uns die Implementierung f&#252;r das parsen und erstellen d. Abfrage, sowie das Weiterreichen f&#252;r die Ausf&#252;hrung vorzunehmen. 

  

  Basierend auf dieser Grundfunktionalit&#228;t k&#246;nnen wir nun unsere eigentliche Aufgabestellung umsetzen. Mehr dazu jedoch im 2ten Teil. Stay tuned. 

  

  Sie m&#246;chten mehr wissen zum Thema? Auf der ADC08 gibt es eine Session von mir: 

  

  </description>
			<link>http://blogs.ppedv.de/bernhardg/archive/LINQ-Provider---Vom-Ausdruck-zum-Ergebnis</link>
			<author>Bernhard Grojer </author>
			<pubDate>Wed, 24 Sep 2008 13:17:37 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] Internet Explorer 8 - Beta 2 (Deutsch/Englisch/...)</title>
			<description>   Ab heute gibt es die Beta 2 des IE 8. Download und Informationen sind hier zu finden.     </description>
			<link>http://blogs.ppedv.de/bernhardg/archive/Internet-Explorer-8---Beta-2-DeutschEnglisch...</link>
			<author>Bernhard Grojer </author>
			<pubDate>Thu, 28 Aug 2008 08:53:42 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] .net Framework 3.5 SP1 - RTM</title>
			<description>   Mit dem SQL Server 2008 haben wir auch das SP1 f&#252;r .net Framework 3.5 (Link im Moment noch beta) bekommen.         Doch leider fehlt uns noch Visual Studio 2008 SP1 damit wir SQL Server 2008 neben Visual Studio 2008 installieren k&#246;nnen.         Dies soll sich allerdings am Montag &#228;ndern. SP1 soll am 11. August 08 inkl. EntityFramework via MSDN verf&#252;gbar werden.     </description>
			<link>http://blogs.ppedv.de/bernhardg/archive/.net-Framework-3.5-SP1---RTM</link>
			<author>Bernhard Grojer </author>
			<pubDate>Thu, 07 Aug 2008 23:19:30 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] SQL Server 2008 - RTM</title>
			<description>   Ab heute ist die RTM Version des SQL Server 2008 verf&#252;gbar und kann &#252;ber MSDN geladen werden.         Eine Trail-Version der Enterprise-Variante gibt es hier.</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/SQL-Server-2008---RTM</link>
			<author>Bernhard Grojer </author>
			<pubDate>Thu, 07 Aug 2008 20:57:24 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] .net 3.5 - SP1 / VS 2008 - SP1</title>
			<description>... nein das ist nicht das ultimative &quot;.net 3.5 SP1 Final&quot; Posting. Aber vermutlich dauert es nicht mehr allzu lange, denn Microsoft plant den release noch diesen Sommer.         Im Moment kann man bereits eine &#246;ffentliche Beta downloaden und sich daran versuchen.         Doch was erwartet uns mit dem Servicepack?         .net Framework 3.5 - SP1:     Performance, Performance, Performance (WPF bis zu 45% ohne Code&#228;nderung)     WCF     ADO.net Entity Framework, ADO.net Data Services, SQL Server 2008 Features     .net 3.5 Client Runtime (Ein 20 MB gro&#223;es .net Paket um nicht immer gezwungen zu sein, das komplette .net Framework auf die Clients zu installieren)     Und mehr ...   Visual Studio 2008 - SP1:     Unterst&#252;tzung f&#252;r SQL Server 2008     Verbesserter WPF Designer (Stichwort grafische Oberfl&#228;che f&#252;r Events, ...)     Verbesserungen bei TFS     Und mehr ...  </description>
			<link>http://blogs.ppedv.de/bernhardg/archive/.net-3.5---SP1--VS-2008---SP1</link>
			<author>Bernhard Grojer </author>
			<pubDate>Fri, 01 Aug 2008 10:50:19 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
		<item>
			<title>[Bernhard Grojer] Parallel Extensions - June 2008 CTP</title>
			<description>   In der Zwischenzeit tut sich bei der Leistung die eine einzige CPU bringt leider nur mehr sehr wenig. Allerdings bekommen wir immer Mehr CPU(Kerne) die unsere Aufgaben erledigen k&#246;nnen.         Doch - Sie wissen das sicherlich schon - ist Mutlithreading in der eigenen Anwendung immer ein Aufwand und oftmals nicht so einfach umsetzbar.         Microsoft arbeitet allerdings seit einiger Zeit an den Prallel Extensions f&#252;r das .net Framework 3.5. Im Moment haben wir die June 2008 CTP verf&#252;gbar.         Ich wollte die Sache daher gleich mal testen. Und zwar wollte ich alle Primzahlen in einen gewissen Zahlenbereich berechnen lassen (brute-force)             1:          public List&lt;int&gt; GetPrimeNumbers(int lowerLimit, int upperLimit)

     2:          {

     3:              var lst = new List&lt;int&gt;();

     4:              for (int i = lowerLimit; i &lt; upperLimit; i++)

     5:              {

     6:                  if (IsPrime(i))

     7:                      lst.Add(i);

     8:              }

     9:              return lst;

    10:          }

    11:  &#160;

    12:          public bool IsPrime(int n)

    13:          {

    14:              for (int i = 2; i &lt; n; i++)

    15:              {

    16:                  if (n % i == 0)

    17:                      return false;

    18:              }

    19:              return true;

    20:          }



.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; }

Die Funktion GetPrimeNumbers gibt daraufhin alle Primzahlen retour. Allerdings - welche &#220;berraschung - wird die Sache nur auf einen Kern ausgef&#252;hrt. WIr verschenken daher auf Dual Cores bereits 50% Leistung. 
  

  Also versuchen wir das Problem zu umschiffen und F&#252;gen folgende Methode hinzu: 

  


     1:          public List&lt;int&gt; GetPrimeNumbersParallel(int lowerLimit, int upperLimit)

     2:          {

     3:              var lst = new List&lt;int&gt;();

     4:              Parallel.For(lowerLimit, upperLimit, delegate(int i)

     5:                              {

     6:                                  if (IsPrime(i))

     7:                                      lst.Add(i); 

     8:                              }

     9:                          );

    10:  &#160;

    11:              return lst;

    12:          }



.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; }

In Zeile 4 verwenden wir nun die Prallel.For Methode (System.Threading) der Parallel Extensions und somit haben wir einen Methode entwickelt die all unsere Kerne nutzt ohne uns zu (manuellen) Threading zu zwingen. 
  

  Nun zu unserem Aufruf: 

  


     1:              Stopwatch sw;

     2:              var pn = new PrimeNumber();

     3:              var startNumber = 2;

     4:              var endNumber = 500000;

     5:  &#160;

     6:              sw = Stopwatch.StartNew();

     7:              var res1 = pn.GetPrimeNumbers(startNumber, endNumber);

     8:              Console.WriteLine(&quot;Done Seq: {0}&quot;, sw.ElapsedMilliseconds);

     9:  &#160;

    10:              sw = Stopwatch.StartNew();

    11:              var res2 = pn.GetPrimeNumbersParallel(startNumber, endNumber);

    12:              Console.WriteLine(&quot;Done Parallel: {0}&quot;, sw.ElapsedMilliseconds);



.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; }

Wir m&#252;ssen beim Aufruf selbst nichts mehr beachten.


  &#160;

Das Ergebnis kann sich sehen lassen w&#252;rde ich sagen. 
  

  Download des Samples gibts hier.</description>
			<link>http://blogs.ppedv.de/bernhardg/archive/Parallel-Extensions---June-2008-CTP</link>
			<author>Bernhard Grojer </author>
			<pubDate>Fri, 18 Jul 2008 10:07:14 GMT</pubDate>
			<category domain="http://blogs.ppedv.de?tag=">
			
			</category>
			
		</item>
	
	        </channel>
		</rss>
	
    
    

