ObservableCollection<(Of <(T>)>) Class

    [SerializableAttribute]
    public class ObservableCollection<T> : Collection<T>,
    INotifyCollectionChanged, INotifyPropertyChanged

    In many cases the data that you work with is a collection of objects. For example, a common scenario in data binding is to use an ItemsControl such as a ListBox, ListView, or TreeView to display a collection of records.

    You can enumerate over any collection that implements the IEnumerable interface. However, to set up dynamic bindings so that insertions or deletions in the collection update the UI automatically, the collection must implement the INotifyCollectionChanged interface. This interface exposes the CollectionChanged event, an event that should be raised whenever the underlying collection changes.

    WPF provides the ObservableCollection<(Of <(T>)>) class, which is a built-in implementation of a data collection that implements the INotifyCollectionChanged interface.

    Before implementing your own collection, consider using ObservableCollection<(Of <(T>)>) or one of the existing collection classes, such as List<(Of <(T>)>), Collection<(Of <(T>)>), and BindingList<(Of <(T>)>), among many others. If you have an advanced scenario and want to implement your own collection, consider using IList, which provides a non-generic collection of objects that can be individually accessed by index. Implementing IList provides the best performance with the data binding engine.

    Note:

    To fully support transferring data values from binding source objects to binding targets, each object in your collection that supports bindable properties must implement an appropriate property changed notification mechanism such as the INotifyPropertyChanged interface.

    For more information, see "Binding to Collections" in Data Binding Overview.

    Notes on XAML Usage

    ObservableCollection<(Of <(T>)>) can be used as a XAML object element in Windows Presentation Foundation (WPF), in versions 3.0 and 3.5. However, the usage has substantial limitations.

    • ObservableCollection<(Of <(T>)>) must be the root element, because the x:TypeArguments attribute that must be used to specify the constrained type of the generic ObservableCollection<(Of <(T>)>) is only supported on the object element for the root element.
    • You must declare an x:Class attribute (which entails that the build action for this XAML file must be Page or some other build action that compiles the XAML).
    • ObservableCollection<(Of <(T>)>) is in a namespace and assembly that are not initially mapped to the default XML namespace. You must map a prefix for the namespace and assembly, and then use that prefix on the object element tag for ObservableCollection<(Of <(T>)>).

    A more straightforward way to use ObservableCollection<(Of <(T>)>) capabilities from XAML in an application is to declare your own non-generic custom collection class that derives from ObservableCollection<(Of <(T>)>), and constrains it to a specific type. Then map the assembly that contains this class, and reference it as an object element in your XAML.

    This example

    This example shows how to create and bind to a collection that derives from the ObservableCollection<(Of <(T>)>) class, which is a collection class that provides notifications when items get added or removed.

    The following example shows the implementation of a NameList collection:

    public class PersonName
    
    {
    
    private string firstName;
    
    private string lastName;
    
    public PersonName(string first, string last)
    
    {
    
    	this.firstName = first;
    
    	this.lastName = last;
    
    }
    
    public string FirstName
    
    {
    
    	get { return firstName; }
    
    	set { firstName = value; }
    
    }
    
    public string LastName
    
    {
    
    	get { return lastName; }
    
    	set { lastName = value; }
    
    }
    
    }
    
    public class NameList : ObservableCollection<PersonName>
    
    {
    
    public NameList() : base()
    
    {
    
    	Add(new PersonName("Willa", "Cather"));
    
    	Add(new PersonName("Isak", "Dinesen"));
    
    	Add(new PersonName("Victor", "Hugo"));
    
    	Add(new PersonName("Jules", "Verne"));
    
    }
    
    }
    

    데이터 삽입 방법(ADO.NET 데이터 서비스/Silverlight)

    System.Data.Services.Client 라이브러리를 사용하는 Silverlight 응용 프로그램에서는 ADO.NET 데이터 서비스에 데이터를 삽입할 수 있습니다. 이 단원의 코드 시나리오에서는 데이터 모델 및 데이터 서비스 구현(ADO.NET 데이터 서비스/Silverlight)에 설명되어 있는 데이터 서비스를 사용합니다. 이 항목에서는 클라이언트 응용 프로그램이 사용자 지정 항목을 System.Data.Services.Client..::.DataServiceContext의 로컬 인스턴스에 추가하여 Northwind 데이터 서비스의 저장소에 유지하는 방법을 보여 줍니다.

    이 예제의 쿼리는 LINQ 구문을 사용하며 미국 지역 고객을 식별하는 where 절을 포함합니다. 비동기 메서드는 서비스에서 데이터를 가져와서 Customer 형식의 ObservableCollection<T>으로 읽어 옵니다. 이 컬렉션은 데이터 표의 DataServiceContext에 할당됩니다.

    Silverlight 응용 프로그램

    Silverlight 응용 프로그램을 구현하려면

    1. 데이터 모델 및 데이터 서비스 구현(ADO.NET 데이터 서비스/Silverlight)에 설명되어 있는 ASP.NET 웹 응용 프로그램을 만들거나 다시 사용합니다.

    2. Visual Studio 솔루션 탐색기에서 솔루션을 마우스 오른쪽 단추로 클릭하고 추가를 가리킨 다음 새 항목을 선택합니다.

    3. 새 항목 추가 대화 상자에서 Silverlight 범주의 새 프로젝트를 추가합니다. 프로젝트 이름을 SilverlightClientApp2로 지정합니다.

    4. Silverlight 응용 프로그램 추가 대화 상자에서 Silverlight 컨트롤을 기존 웹 사이트에 연결, 응용 프로그램을 참조하는 테스트 페이지 추가 및 시작 페이지로 만들기를 선택합니다.

    5. ASP.NET 웹 응용 프로그램 속성 페이지에서 웹/시작 작업 섹션에 특정 페이지가 선택되어 있는지 확인합니다. 새 프로젝트의 *.html 테스트 페이지를 사용합니다. 그러면 텍스트 상자에 Silverlight 응용 프로그램 HTML 테스트 페이지가 시작 페이지로 표시됩니다.

    중요:

    ADO.NET 데이터 서비스의 Silverlight 클라이언트는 데이터 서비스 호스트와 동일한 도메인에 있어야 합니다. 예를 들어 클라이언트 응용 프로그램이 http://domain-x/SilverlightApp.html에 있는 경우 http://domain-x/dataservice.svc로 데이터 서비스 요청을 보내면 클라이언트와 데이터 서비스가 같은 도메인에 있으므로 요청이 성공합니다. 도메인 x에 있는 클라이언트 응용 프로그램에서 http://domain-z/dataservice.svc로 요청을 보내면 대상 데이터 서비스가 다른 도메인에 있으므로 요청이 실패합니다.

    Silverlight 사용자 인터페이스

    이 예제의 사용자 인터페이스에는 System.Windows.Controls.Data 어셈블리의 DataGrid 컨트롤과 StackPanel이 포함됩니다. 데이터 표에서는 Silverlight용 클라이언트 응용 프로그램(ADO.NET 데이터 서비스/Silverlight)에 구현된 것과 유사한 데이터 바인딩 시나리오를 사용하여 데이터를 표시합니다. 이전 예제의 목록 상자와는 달리 데이터 표에 바인딩할 때 페이지 스키마에 데이터 템플릿을 정의하지 않아도 됩니다.

    사용자 인터페이스를 구현하려면

    1. 프로젝트에 System.Windows.Controls.Data에 대한 참조를 추가합니다.

    2. 클라이언트 응용 프로그램의 Page.xaml 파일에 xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" xmlns 참조를 추가합니다.

    3. UserControl 블록은 다음과 같습니다.

      <UserControl x:Class="SilverlightClientApp2.Page"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
          Width="800" Height="400">
    4. 다음과 같이 Page.xaml 파일의 Grid 요소에 RowDefinitions를 추가합니다.

      <Grid x:Name="LayoutRoot" Background="White">
              <Grid.RowDefinitions>
                  <RowDefinition Height="*"/>
                  <RowDefinition Height="4*"/>
              </Grid.RowDefinitions>
          </Grid>
    5. Grid에 StackPanel을 추가합니다.

              <StackPanel Orientation="Horizontal">
              </StackPanel>
    6. 다음 XML 예제에 표시된 것과 같이 StackPanel에 단추와 텍스트 상자를 추가합니다. 텍스트 상자에는 새 Customer에 대한 데이터를 입력할 수 있습니다. Get Data 단추와 Insert 단추에 Click을 할당하면 이 사용자 인터페이스의 코드에서 처리기 메서드가 해당 단추에 할당됩니다.

              <StackPanel Orientation="Horizontal">
                   <Button Content="Get Data" 
                      Width="75"
                      Height="20"
                      Margin="10" 
                      Click="OnGetData"/>
                  <Button Content="Insert" 
                      Width="75"
                      Height="20"
                      Margin="10"  
                      Click="OnInserted"/>
                  <TextBox Text="IDXXX" 
                      Width="75"
                      Height="25"
                      Margin="10" 
                      Name="textBoxCustomerID"/>
                  <TextBox Text="CompanyName" 
                      Width="75"
                      Height="25"
                      Margin="10" 
                      Name="textBoxCompanyName"/>
              </StackPanel>
    7. System.Windows.Controls.Data 어셈블리에서 DataGrid 컨트롤을 추가합니다. Northwind 데이터를 표시할 수 있도록 ItemsSource 특성을 {Binding}으로 설정합니다.

              <data:DataGrid 
                  Name="dataGrid1"
                  Grid.Row="1" 
                  Margin="20"
                  AutoGenerateColumns="True" 
                  ItemsSource="{Binding}" >
              </data:DataGrid>

    다음은 완성된 Page.xaml 파일입니다.

    <UserControl x:Class="SilverlightClientApp2.Page"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
        Width="800" Height="400">
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="4*" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <StackPanel Orientation="Horizontal">
                <Button Content="Get Data" 
                    Width="75"
                    Height="20"
                    Margin="10" 
                    Click="OnGetData"/>
                <Button Content="Insert" 
                    Width="75"
                    Height="20"
                    Margin="10"  
                    Click="OnInserted"/>
                <TextBox Text="IDXXX" 
                    Width="75"
                    Height="25"
                    Margin="10" 
                    Name="textBoxCustomerID"/>
                <TextBox Text="CompanyName" 
                    Width="75"
                    Height="25"
                    Margin="10" 
                    Name="textBoxCompanyName"/>
            </StackPanel>
            
            <TextBlock x:Name="CustomerBlock" Grid.Row="1" 
               Text="Customers:" Grid.Column="0" FontFamily="Calibri"/>
    
            <data:DataGrid 
                Name="dataGrid1"
                Grid.Row="2" 
                Margin="10"
                AutoGenerateColumns="True" 
                ItemsSource="{Binding}" >
            </data:DataGrid>
            
            <TextBlock x:Name="textBlock" Grid.Row="3" Text=""
                       Grid.Column="0" FontFamily="Calibri"/>
            
        </Grid>
    </UserControl>

    데이터 표시 및 삽입을 위한 클라이언트 코드

    사용자 인터페이스에서 dataGrid1의 ItemsSource는 데이터 바인딩을 지정합니다. ADO.NET 데이터 서비스에 대한 데이터 바인딩을 사용하려면 클라이언트 메서드에서 데이터 서비스의 응답을 기다려야 하므로 비동기 메서드를 사용해야 합니다.

    데이터 바인딩 및 표시

    Northwind 데이터 서비스에서 Customer 데이터를 가져오고 표시하려면

    1. 참조를 추가하거나, Silverlight 프로젝트에서 다음 어셈블리를 참조하는지 확인한 후 이러한 어셈블리에 대한 using 지시문을 Page.xaml.cs 파일에 추가합니다.

      using System.Data.Services.Client;
      using System.Collections.ObjectModel;
    2. 데이터 서비스 클래스에 대한 using 지시문을 Page.xaml.cs 파일에 추가합니다.

      using SilverlightClientApp2.NorthwindSvc;
    3. 다음 코드 예제와 같이 페이지 초기화 코드를 구현합니다. NorthwindEntities 클래스는 이 응용 프로그램에서 사용하는 DataServiceContext 클래스를 구현한 것입니다. 다음 코드를 사용하면 Silverlight 페이지가 로드될 때 DataServiceContext가 초기화됩니다. 6단계에 설명된 것처럼 데이터 바인딩에는 Customer 형식의 ObservableCollection<T>이 사용됩니다.

      namespace SilverlightClientApp2
      {
          public partial class Page : UserControl
          {
              NorthwindEntities svcContext;
              ObservableCollection<Customer> obsvCollCustomers;
      
              public Page()
              {
                  InitializeComponent();
                  this.Loaded += OnLoaded;
              }
      
              void OnLoaded(object sender, EventArgs args)
              {
                  svcContext = new NorthwindEntities(
                          new Uri("Northwind.svc", UriKind.Relative));
                  obsvCollCustomers = new
                                     ObservableCollection<Customer>();
              }
    4. 다음 코드와 같이 Get Data 단추의 Click 메서드에 지정된 메서드를 구현합니다. Customer 형식의 DataServiceQuery<(Of <(TElement>)>)을 만듭니다. 이 예제에서는 where 절과 select 문이 포함된 LINQ 구문을 사용합니다. 쿼리를 정의한 후에는 비동기 메서드 BeginExecute를 호출합니다. 메서드의 첫 번째 매개 변수는 데이터 서비스에서 결과를 반환할 때 쿼리를 완료할 콜백 함수를 식별합니다.

              void OnGetData(object sender, EventArgs args)
              {
                  DataServiceQuery<Customer> query =
                      (DataServiceQuery<Customer>)
                      (from c in svcContext.Customers 
                       where c.Country == "USA"
                       select c);
      
                  query.BeginExecute(GetDataCallback, query);
      
              }
    5. 이전 단계에서 시작된 쿼리의 결과를 처리하는 콜백 함수를 구현합니다. 비동기 작업의 결과는 결과 매개 변수에 포함된 IAsyncResult.AsyncState 개체에 들어 있습니다. AsyncState를 Customer 형식의 DataServiceQuery<(Of <(TElement>)>)로 캐스팅하여 쿼리 결과를 열거합니다.

    6. Customer 형식의 ObservableCollection<T>을 초기화합니다. 이 클래스는 변경 사항이 발생했을 때 알림을 보내기 때문에 데이터 바인딩에 사용됩니다. 이 방법은 데이터 변경 사항을 데이터 서비스에 저장한 후에 비동기 메서드에서 반환하는 경우 유용합니다. 쿼리 결과를 처리하는 스레드에서 사용자 인터페이스 스레드에 대해 프로시저를 호출하려면 Dispatcher 개체가 필요합니다. Dispatcher 대괄호 안에서 호출되는 코드는 고객의 ObservableCollection을 dataGrid1의 DataContext 속성에 할당합니다.

              void GetDataCallback(IAsyncResult result)
              {
                  try
                  {
                      DataServiceQuery<Customer> queryResult =
                                     (DataServiceQuery<Customer>) result.AsyncState;
      
                      IEnumerable<Customer> results =
                                    queryResult.EndExecute(result);
      
                      foreach (var item in results)
                              obsvCollCustomers.Add(item);
      
                      Dispatcher.BeginInvoke(() =>
                      {
                          dataGrid1.DataContext = obsvCollCustomers;
                      });
                  }
                  catch (DataServiceRequestException ex)
                  {
                      textBlock.Text = "Error: " + ex.Response.ToString();
                  }
              }
      
    7. 응용 프로그램을 빌드하고 실행합니다. Get Data 단추를 클릭하면 페이지의 데이터 표가 Northwind 데이터 서비스에서 가져온 고객으로 채워집니다.

    데이터 삽입

    Silverlight 사용자 인터페이스에서 Customer 데이터 형식의 새 인스턴스를 만들어 데이터 서비스에 삽입하려면

    1. Insert 단추의 Click 메서드에 지정된 OnInserted 메서드를 구현합니다. OnInserted 메서드는 Customer 데이터 형식의 새 인스턴스를 만든 다음 페이지의 텍스트 상자에 있는 데이터로부터 null을 허용하지 않는 CustomerID 및 CompanyName 속성을 할당합니다. OnGetData에서 DataServiceQuery<(Of <(TElement>)>)의 where 절은 Country == USA인 결과를 지정하므로 Country 속성을 할당합니다. 그런 다음에는 컨트롤에 표시되는 데이터에 새 항목을 표시하기 원할 수 있습니다. 모든 할당 작업이 완료되면 Northwind 서비스의 DataServiceContext를 사용하여 새 Customer를 추가합니다. 클라이언트 클래스에서 제공하는 AddToCustomers 메서드를 호출하여 Customer를 추가합니다. 그런 다음 콜백 함수와 새 Customer 인스턴스를 식별하는 매개 변수를 사용하여 System.Data.Services.Client 라이브러리에서 BeginSaveChanges 메서드를 호출합니다.

              void OnInserted(object sender, EventArgs args)
              {
                  Customer newCustomer = new Customer();
                  newCustomer.CustomerID = textBoxCustomerID.Text;
                  newCustomer.CompanyName = textBoxCompanyName.Text;
                  newCustomer.Country = "USA";
      
                  svcContext.AddToCustomers(newCustomer);
                  svcContext.BeginSaveChanges(OnSaveChangesCompleted, newCustomer);
      
              }
      
    2. OnSaveChangesCompleted를 구현하여 이전 단계에서 호출한 BeginSaveChanges의 비동기 결과를 처리합니다. 콜백 함수는 DataServiceContextEndSaveChanges 멤버를 사용하여 Northwind svcContext를 통해 데이터 서비스의 데이터를 업데이트합니다. IAsyncResultObservableCollection 개체를 Customer 형식으로 캐스팅하여 ObservableCollection ObsvCollCustomers에 추가할 수 있습니다. 이렇게 하면 데이터 표가 자동으로 업데이트됩니다.

              void OnSaveChangesCompleted(IAsyncResult result)
              {
                  try
                  {
                      proxy.EndSaveChanges(result);
                      // Add the new customer to the grid.
                      obsvCollCustomers.Add(result.AsyncState as Customer);
                      textBlock.Text = "Insert complete: " +
                                     (result.AsyncState as Customer).CustomerID;
                  }
                  catch (DataServiceRequestException ex)
                  {
                      textBlock.Text = "OnSaveChangesCompleted Error: " + ex.Response.ToString();
                  }
              }
      

    응용 프로그램을 실행합니다. IDXXX 텍스트 상자에 다섯 자로 된 고객 ID를 입력하고 CompanyName 텍스트 상자에 회사 이름을 입력합니다. Insert 단추를 클릭하여 새 고객을 추가하고, 새 항목이 포함된 결과로 데이터 표를 업데이트합니다.

    다음 코드에서는 이 항목에서 사용된 Page.xaml.cs 파일의 전체 콘텐츠를 보여 줍니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    
    using System.Data.Services.Client;
    using System.Collections.ObjectModel;
    using SilverlightClientApp2.NorthwindSvc;
    
    
    namespace SilverlightClientApp2
    {
        public partial class Page : UserControl
        {
            NorthwindEntities proxy;
            ObservableCollection<Customer> obsvCollCustomers;
    
            public Page()
            {
                InitializeComponent();
                this.Loaded += OnLoaded;
            }
    
            void OnLoaded(object sender, EventArgs args)
            {
                proxy = new NorthwindEntities(
                        new Uri("Northwind.svc", UriKind.Relative));
                obsvCollCustomers = new
                                   ObservableCollection<Customer>();
            }
    
            void OnGetData(object sender, EventArgs args)
            {
                DataServiceQuery<Customer> query =
                    (DataServiceQuery<Customer>)
                    (from c in proxy.Customers
                     where c.Country == "USA"
                     select c);
    
                query.BeginExecute(GetDataCallback, query);
    
            }
    
            void GetDataCallback(IAsyncResult result)
            {
                try
                {
                    DataServiceQuery<Customer> queryResult =
                                   (DataServiceQuery<Customer>)result.AsyncState;
    
                    IEnumerable<Customer> results =
                                  queryResult.EndExecute(result);
    
                    foreach (var item in results)
                        obsvCollCustomers.Add(item);
    
                    Dispatcher.BeginInvoke(() =>
                    {
                        dataGrid1.DataContext = obsvCollCustomers;
                    });
                }
                catch(DataServiceRequestException ex)
                {
                    ex.Response.ToString();
                }
            }
    
            void OnInserted(object sender, EventArgs args)
            {
                Customer newCustomer = new Customer();
                newCustomer.CustomerID = textBoxCustomerID.Text;
                newCustomer.CompanyName = textBoxCompanyName.Text;
                newCustomer.Country = "USA";
    
                proxy.AddToCustomers(newCustomer);
                proxy.BeginSaveChanges(OnSaveChangesCompleted, newCustomer);
    
            }
    
            void OnSaveChangesCompleted(IAsyncResult result)
            {
                try
                {
                    proxy.EndSaveChanges(result);
    
                    obsvCollCustomers.Add(result.AsyncState as Customer);
                    textBlock.Text = "Insert complete: " +
                                       (result.AsyncState as Customer).CustomerID;
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "OnSaveChangesCompleted Error: " + ex.Response.ToString();
                }
            }
        }
    }
    

    System.Data.Services.Client 라이브러리를 사용하는 Silverlight용 응용 프로그램에서는 ADO.NET 데이터 서비스에서 배포되는 데이터를 업데이트 및 삭제할 수 있습니다. 이 항목의 코드는 데이터 삽입 방법(ADO.NET 데이터 서비스/Silverlight) 항목에서 설명한 시나리오를 확장하고 이전 예제에 구현된 ASP.NET 웹 응용 프로그램을 사용합니다.

    데이터를 업데이트 및 삭제하는 클라이언트 코드

    데이터를 업데이트할 때는 이전 예제에 표시된 것과 비슷한 동기화 메서드를 사용합니다. 다음 예제에서는 Category 데이터 형식을 사용하여 업데이트 및 삭제 절차를 설명합니다. Category 데이터 형식은 Product 데이터에만 연결됩니다.

    참고:

    데이터를 업데이트할 때는 데이터 모델을 분석하여 연결이 제대로 업데이트되는지 확인해야 합니다. Northwind 데이터 서비스에서 Customer 항목은 여러 Order 데이터 인스턴스와 연결할 수 있으며 각 Order는 여러 Order_Detail 항목과 연결할 수 있습니다. 데이터 서비스에서 액세스할 수 있는 관계형 모델에 제한이 있기 때문에 Customer 또는 Order를 삭제하기 위해서는 Customer, Order 및 Order_Detail 항목이 연관된 모든 연결을 삭제해야 할 수 있습니다. 연결에 대한 자세한 내용은 엔터티 및 관계 또는 엔터티 데이터 모델 관계를 참조하십시오.

    Silverlight 사용자 인터페이스

    이 Silverlight용 응용 프로그램의 사용자 인터페이스는 다음 XML 예제에서 보는 것처럼 Page.xaml 스키마에서 초기화됩니다. 이 페이지에는 세 행으로 구성된 표가 있습니다. 0행은 데이터 수정 및 삭제를 실행하는 단추가 있는 가로 스택 패널이고, 1행에는 데이터 표가 있습니다. 2행은 데이터가 로드되거나 오류가 발생할 때 메시지가 표시되는 텍스트 블록입니다.

    <UserControl x:Class="SilverlightClientApp3.Page"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
        Width="800" Height="800">
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="3*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition MaxWidth="650"/>
            </Grid.ColumnDefinitions>
    
            <StackPanel Orientation="Horizontal"
                            Grid.Column="0" Grid.Row="0">
                <Button Content="Delete" 
                    Width="75"
                    Height="20"
                    Margin="10" 
                    Click="OnDelete"/>
                <Button Content="Commit"
                    Width="75"
                    Height="20"
                    Margin="10"  
                    Click="OnUpdate"/>
            </StackPanel>
    
            <data:DataGrid 
                Name="dataGrid1"
                Grid.Row="1" 
                Grid.Column="0"
                AutoGenerateColumns="True"
                ItemsSource="{Binding}" >
            </data:DataGrid>
    
            <TextBlock x:Name="textBlock" Grid.Row="2"
                   Grid.Column="0" FontFamily="Calibri"/>
        </Grid>
    </UserControl>
    데이터 업데이트

    ADO.NET 데이터 서비스에서 배포하는 데이터를 업데이트하려면 Silverlight용 응용 프로그램에서 다음 비동기 절차를 구현해야 합니다.

    1. UpdateObject 메서드를 호출하여 클라이언트 응용 프로그램에서 DataServiceContext의 데이터를 수정합니다. 이 경우 서버의 데이터는 수정되지 않지만 BeginSaveChanges 메서드가 호출될 때 업데이트를 위해 데이터가 변경된 것으로 표시됩니다.

    2. 첫 번째 매개 변수에서 지정한 콜백 함수로 BeginSaveChanges 메서드를 호출합니다.

    3. 콜백 함수에서 EndSaveChanges 메서드를 호출하여 BeginSaveChanges 메서드의 결과를 처리합니다.

    다음 코드 세그먼트는 업데이트 시나리오의 각 단계를 보여 줍니다.

    다음 예제의 OnUpdate 메서드는 사용자가 데이터 표의 데이터를 수정하고 커밋 단추를 클릭하여 선택한 행의 변경 사항을 커밋할 때 실행됩니다. 이 예제에서는 한 번에 한 행만 업데이트합니다. Category 항목은 DataGridEndingEditEventArgs 개체의 SelectedItem을 Category 형식에 캐스팅하여 업데이트하도록 지정됩니다. 이 Category 항목을 변경하면 UpdateObject 메서드를 호출하여 클라이언트 응용 프로그램의 DataServiceContext에서 업데이트됩니다. BeginSaveChanges 메서드는 데이터 서비스 업데이트를 위한 비동기화 프로세스를 시작합니다.

            void OnUpdate(object sender, EventArgs args)
            {
                if (dataGrid1.SelectedItem == null || dataGrid1.SelectedItems.Count > 1)
                {
                    textBlock.Text = "Select a single row for update.";
                    return;
                }
    
                Category selectedCategory = (Category)dataGrid1.SelectedItem;
    
                try
                {
                    svcContext.UpdateObject(selectedCategory);
                    textBlock.Text = "Saving Changes...";
                    svcContext.BeginSaveChanges(OnSaveChangesCompleted, selectedCategory);
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "OnUpdate Error: " + ex.Response.ToString();
                }
            }

    데이터 서비스에서 OnUpdate 메서드의 결과가 반환되면 콜백 메서드 OnSaveChangesCompleted가 EndSaveChanges를 호출하여 업데이트를 완료합니다.

            void OnSaveChangesCompleted(IAsyncResult result)
            {
                try
                {
                    svcContext.EndSaveChanges(result);
                    textBlock.Text = "Completed";
    
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "OnSaveChangesCompleted Error: " + ex.Response.ToString();
                }
            }
    
    데이터 삭제

    Northwind 데이터 서비스에서 배포하는 Category 데이터를 삭제하려면 Silverlight용 응용 프로그램에서 다음 비동기 절차를 구현해야 합니다.

    1. 콜백 함수로 BeginLoadProperty 메서드를 호출하여 비동기 메서드의 결과를 처리함으로써 삭제할 항목과 연관된 항목을 모두 가져옵니다. 데이터 서비스는 외부 키 제약 조건이 있는 데이터베이스를 기반으로 하기 때문에 관련된 항목을 모두 삭제해야 합니다.

    2. EndLoadProperty 메서드가 단계 1의 결과를 가져오는 콜백 메서드를 구현합니다.

    3. 각 항목에서 DeleteLink 메서드를 호출하여 관련 항목의 바인딩을 해제합니다.

    4. DeleteObject 메서드를 호출하여 항목을 삭제합니다.

    5. 첫 번째 매개 변수에서 지정한 콜백 함수로 BeginSaveChanges 메서드를 호출합니다.

    6. 콜백 함수에서 EndSaveChanges 메서드를 호출하여 BeginSaveChanges 메서드의 결과를 처리합니다.

    사용자가 삭제 단추를 클릭하면 OnDelete 메서드가 트리거되어 Northwind 서비스에서 Category 항목을 삭제하는 일련의 비동기 메서드가 시작됩니다. OnDelete 메서드는 삭제할 Category를 가져온 다음 비동기 메서드 BeginUnBindDeleteCategory로 전달합니다.

            void OnDelete(object sender, EventArgs args)
            {
                if (dataGrid1.SelectedItem != null)
                {
                    try
                    {
                        Category Category = (Category)dataGrid1.SelectedItem;
    
                        BeginUnBindDeleteCategory(Category);
                        textBlock.Text = "Saving Changes...";
    
                    }
                    catch (DataServiceRequestException ex)
                    {
                        textBlock.Text = "OnDelete Error: " + ex.Response.ToString();
                    }
                }
            }
    

    BeginUnBindDeleteCategory 메서드는 이전 단계에서 지정한 Category 항목과 연관된 Product 항목을 로드하기 시작합니다. BeginLoadProperty 메서드의 두 번째 매개 변수는 결과를 처리할 콜백 함수, 이 경우에는 EndUnBindDeleteCategory를 지정합니다.

            void BeginUnBindDeleteCategory(Category categoryObject)
            {
                try
                {//기본적으로 관계 속성(예: Product.Supplier)이 있을 때 속성을 명시적으로 로드하지 않으면 해당 속성은 Null이 됩니다. //필요 시 로딩을 지원하기 위해 DataServiceContext 클래스에는 동일한 비동기 모델을 따르는 BeginLoadProperty 메서드가 있습니다. //이 메서드에서 원본 엔터티, 속성 이름 및 콜백을 지정할 수 있습니다. (테이블의 고유키라고 보면됩니다.)                                svcContext.BeginLoadProperty(categoryObject, "Products",
                                   EndUnBindDeleteCategory, categoryObject);
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "BeginUnBindDeleteCategory Error: " + ex.Response.ToString();
                }
            }
    



     

    EndUnBindDeleteCategory 메서드는 BeginLoadProperty 메서드의 결과를 처리할 EndLoadProperty 메서드를 호출합니다. 결과는 각 항목에서 DeleteLink 메서드를 호출하는 foreach 루프에 열거되는 연관된 Product 항목입니다.

    연관된 Product 항목에 대한 모든 링크가 Category 항목에서 삭제되면 DeleteObject 메서드를 호출하여 Category 항목이 마지막으로 삭제됩니다. 업데이트 예제에 사용된 콜백 함수인 OnSaveChangesCompleted에서 첫 번째 매개 변수로 BeginSaveChanges 메서드를 호출하여 변경 사항을 데이터 서비스로 전달합니다.

            void EndUnBindDeleteCategory(IAsyncResult asyncResult)
            {
                Category categoryObject = asyncResult.AsyncState as Category;
    
                try
                {
                    svcContext.EndLoadProperty(asyncResult);
    
                    //Unbind all the Products that are bound to this instance 
                    //of Category using the DeleteLink API
                    foreach (Product product in categoryObject.Products)
                    {
                        svcContext.DeleteLink(categoryObject, "Products", product);
                    }
    
                    svcContext.DeleteObject(categoryObject);
                    svcContext.BeginSaveChanges(OnSaveChangesCompleted, null);
                    // Update the grid.
                    obsvCollCategories.Remove(categoryObject);
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "EndUnbindDelete Error: " + ex.Response.ToString();
                }
            }

    OnSaveChangesCompleted 메서드는 EndSaveChanges 메서드를 호출하여 Category 및 Product 항목에 대한 링크의 삭제를 완료합니다.

            void OnSaveChangesCompleted(IAsyncResult result)
            {
                try
                {
                    svcContext.EndSaveChanges(result);
                    textBlock.Text = "Completed";
    
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "OnSaveChangesCompleted Error: " + ex.Response.ToString();
                }
            }
    

    다음 코드에서는 이 항목의 샘플에서 사용하는 Page.xaml.cs 파일의 전체 콘텐츠를 보여 줍니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    
    using SilverlightClientApp3.NorthwindSvc;
    using System.Data.Services.Client;
    using System.Collections.ObjectModel;
    
    namespace SilverlightClientApp3
    {
        public partial class Page : UserControl
        {
            NorthwindEntities svcContext;
            ObservableCollection<Category> obsvCollCategories;
    
            public Page()
            {
                InitializeComponent();
                this.Loaded += OnLoaded;
    
            }
    
            void OnLoaded(object sender, EventArgs args)
            {
                dataGrid1.AutoGeneratingColumn += OnColumnCreated;
    
                svcContext = new NorthwindEntities(
                            new Uri("Northwind.svc", UriKind.Relative));
    
                obsvCollCategories = new ObservableCollection<Category>();
    
                OnGetData(null, null);
            }
    
            void OnColumnCreated(object sender, DataGridAutoGeneratingColumnEventArgs e)
            {
                if (e.PropertyName == "Products" || e.PropertyName == "Picture")
                {
                    e.Cancel = true;
                }
            }
    
            void OnGetData(object sender, EventArgs args)
            {
                DataServiceQuery<Category> query = svcContext.Categories;
    
                try
                {
                    textBlock.Text = "Loading Data...";
    
                    query.BeginExecute(GetDataCallback, query);
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "OnGetData Error: " + ex.Response.ToString();
                }
    
            }
    
            void GetDataCallback(IAsyncResult result)
            {
                try
                {
                    DataServiceQuery<Category> queryResult =
                        (DataServiceQuery<Category>)result.AsyncState;
    
                    IEnumerable<Category> results =
                                       queryResult.EndExecute(result);
    
                        foreach (Category item in results)
                            obsvCollCategories.Add(item);
    
                    Dispatcher.BeginInvoke(() =>
                    {
                        dataGrid1.DataContext = obsvCollCategories;
                    });
    
                    textBlock.Text = "Data Loaded.";
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "GetDataCallback Error: " + ex.Response.ToString();
                }
            }
    
            void BeginUnBindDeleteCategory(Category categoryObject)
            {
                try
                {
                    svcContext.BeginLoadProperty(categoryObject, "Products",
                                   EndUnBindDeleteCategory, categoryObject);
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "BeginUnbindDelete Error: " + ex.Response.ToString();
                }
            }
    
            void EndUnBindDeleteCategory(IAsyncResult asyncResult)
            {
                Category categoryObject = asyncResult.AsyncState as Category;
    
                try
                {
                    svcContext.EndLoadProperty(asyncResult);
    
                    //Unbind all the Products that are bound to this instance 
                    //of Category using the DeleteLink API
                    foreach (Product product in categoryObject.Products)
                    {
                        svcContext.DeleteLink(categoryObject, "Products", product);
                    }
    
                    svcContext.DeleteObject(categoryObject);
                    svcContext.BeginSaveChanges(OnSaveChangesCompleted, null);
                    obsvCollCategories.Remove(categoryObject);
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "EndUnbindDeleteCategory Error: " + ex.Response.ToString();
                }
            }
    
            void OnUpdate(object sender, EventArgs args)
            {
                if (dataGrid1.SelectedItem == null || dataGrid1.SelectedItems.Count > 1)
                {
                    textBlock.Text = "Select a single row for update.";
                    return;
                }
    
                Category selectedCategory = (Category)dataGrid1.SelectedItem;
    
                try
                {
                    svcContext.UpdateObject(selectedCategory);
                    textBlock.Text = "Saving Changes...";
                    svcContext.BeginSaveChanges(OnSaveChangesCompleted, selectedCategory);
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "OnUpdate Error: " + ex.Response.ToString();
                }
            }
    
            void OnDelete(object sender, EventArgs args)
            {
                if (dataGrid1.SelectedItem != null)
                {
                    try
                    {
                        Category Category = (Category)dataGrid1.SelectedItem;
                        BeginUnBindDeleteCategory(Category);
                        textBlock.Text = "Saving Changes...";
    
                    }
                    catch (DataServiceRequestException ex)
                    {
                        textBlock.Text = "OnDelete Error: " + ex.Response.ToString();
                    }
                }
            }
    
            void OnSaveChangesCompleted(IAsyncResult result)
            {
                try
                {
                    svcContext.EndSaveChanges(result);
                    textBlock.Text = "Completed";
                }
                catch (DataServiceRequestException ex)
                {
                    textBlock.Text = "OnSaveChangesCompleted Error: " + ex.Response.ToString();
                }
            }
    
        }
    }

    패턴의 논리적인 뷰

    Cc707885.d7533449 - 4a8a - 31b2 - b258 - 316be0fdaf3f (엉 - 우리, MSDN.10)의 PNG.

    종합 WPF 응용 프로그램에서 프레 젠 테이션 모델 패턴을 사용함으로써,

    개발자들은 데이터 - 바인딩 기능을 윈도우 프리젠 테이션 파운데이션 (WPF)에 의해 제공을 사용할 수있습니다.

    애플 리케이션 데이터에 대한 데이터를 자동으로 그 가치를 변경하면 변경 사항이 반영 묶여있다 요소 바인딩.

    또한, 데이터 바인딩 요소를 변경하는 경우에 데이터의 외부 표현, 기본 데이터를 자동으로 업데이트 될 수있는 변경 사항을 반영하기 위해 의미할 수있습니다. 예를 들어, 사용자가 기본 데이터 값을 자동으로 업데이트 됩니다 그 변경 사항을 반영에 TextBox 요소에서 값을 편집합니다.

     

    보통의 개발단계

    The typical implementation process of the Model-View-Presenter pattern includes the following tasks:

    -Implementing a presenter class . (presenter class  구현)

    -Implementing a view interface. The view interface should expose the view's state elements.( 뷰 인터페이스 구현)

    -Implementing a view class . ( 뷰클래스 구현 )

    Cc707895.8b48bd07 - 0f4f - 4ffc - 8cfd - f2c14a3d57aa (엉 - 우리, MSDN.10)의 PNG.

    일반적인 프로젝트  모습

     

    구현방법

    ViewName Presenter.cs

    class EmployeesPresenter
    {
      private IEmployeesView view;
    
      public EmployeesPresenter (IEmployeesView view)
      {
        this.view = view;
      }
    }
    
    

    view interface는 일반적으로 설정하거나 보기의 상태를 쿼리는 발표자에 대한 하나 이상의 속성이 포함되어있습니다.

    For example, a view could expose an Employee property that allows the presenter to set the employee that the view should display.

    예를 들어, 직원의 견해 발표자보기를 표시해야 그 속성을 설정할 수있는 직원에 노출될 수 있다.

    Another approach consists of using the Presentation Model pattern.

    또 다른 접근 패턴을 사용하여 프레 젠 테이션 모델로 구성되어있습니다.

    In this case, the view interface contains a single property for the presenter to set the presentation model.

    이 경우에는 view interface는 Presentation 모델을 설정할 수있는 presenter  를위한 단일 속성이 포함되어있습니다.

    A different approach consists of exposing methods on the view interface.

    다른 접근 방식을 볼 interface에 노출로 구성되어있습니다.

    For example, the presenter could invoke a method named ShowEmployee ( Employee ) that indicates to the view that it has to display the employee passed by parameter.

    예를 들어, 발표자), 그 직원을 표시하려면이 매개 변수에 의해 통과를 볼 수있는 방법을 나타냅니다 ShowEmployee (Employee)라는 호출할 수있습니다.

    public class EmployeesDetailsPresenter : IEmployeesDetailsPresenter
    {
        public EmployeesDetailsPresenter(IEmployeesDetailsView view)
        {
            this.View = view;
        }
    
        public IEmployeesDetailsView View { get; set; }
    
        public void SetSelectedEmployee(BusinessEntities.Employee employee)
        {
            EmployeesDetailsPresentationModel model = new EmployeesDetailsPresentationModel();
            model.SelectedEmployee = employee;
            this.View.Model = model;
        }
    }
    
    public interface IEmployeesDetailsView
    {
        EmployeesDetailsPresentationModel Model { get; set; }
    }

    1. 기본젝트 구성생성 (NewsAggregtor.Shell.csproj)

    image

    (같이 웹사이트도 생성)

    CAL 관련 참조파일 참조

    Bootstrapper.cs 생성

    using Microsoft.Practices.Composite.UnityExtensions;
    using Microsoft.Practices.Composite.Modularity;
    namespace NewsAggregtor.Shell
    {
        public class Bootstrapper :UnityBootstrapper
        {
            protected override DependencyObject CreateShell()
            {
                Shell shell = new Shell();
                Application.Current.RootVisual = shell;
                return shell;
            }
    
            protected override IModuleCatalog GetModuleCatalog()
            {
                return base.GetModuleCatalog();
            }
        }
    }

    2.Shell.xaml 페이지 생성

    App.xaml 페이지 수정

            private void Application_Startup(object sender, StartupEventArgs e)
            {
                //this.RootVisual = new Page();
                new Bootstrapper().Run();
            }
    

     

     

    2.모듈구성 프로젝트 생성 (NewAggregtor.Digg.csproj)

    image

    CAL 관련 참조파일 참조

    DiggModule.cs 파일 생성

    using Microsoft.Practices.Composite.Modularity;
    
    
    namespace NewsAggregtor.Digg
    {
        public class DiggModule : IModule
        {
    
            #region IModule 멤버
    
            public void Initialize()
            {
               
            }
    
            #endregion
        }
    }

    -------------------------------------------------------------------------------------------------------------------

    모듈프로젝트 생성후 NewsAggregtor.Shell.csproj 프로젝트에서

    모듈프로젝트 참조

    image

     

    NewsAggregtor.Shell.csproj  에서

    모듈관련 프로젝트 참조후 GetModuleCatalog() 메소드 모듈 로드로 수정

    using Microsoft.Practices.Composite.UnityExtensions;
    using Microsoft.Practices.Composite.Modularity;
    namespace NewsAggregtor.Shell
    {
        public class Bootstrapper :UnityBootstrapper
        {
            protected override DependencyObject CreateShell()
            {
                Shell shell = new Shell();
                Application.Current.RootVisual = shell;
                return shell;
            }
    
            protected override IModuleCatalog GetModuleCatalog()
            {
                ModuleCatalog catalog = new ModuleCatalog();
                catalog.AddModule( typeof( NewsAggregtor.Digg.DiggModule) );
                return catalog;
            }
        }
    }

    실행해서 오류 안나면 일단 성공~

    image

     

    두번째 Createing a Modular

    image

    image

     

    DiggSearchResult.xaml 페이지 추가

    <UserControl x:Class="NewsAggregtor.Digg.DiggSearchResult"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="400" Height="300">
        <Grid x:Name="LayoutRoot" Background="White">
            <TextBlock>DiggSearchResult</TextBlock>
        </Grid>
    </UserControl>

    DiggSearchResultView.xaml 페이지 추가

    <UserControl x:Class="NewsAggregtor.Digg.DiggSearchResultView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="400" Height="300">
        <Grid x:Name="LayoutRoot" Background="White">
            <TextBlock>DiggSearchResultView</TextBlock>
        </Grid>
    </UserControl>

     

    NewAggregtor.Digg.csproj 의 DiggModule.cs 수정

    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using Microsoft.Practices.Composite.Modularity;
    using Microsoft.Practices.Composite.Regions;
    namespace NewsAggregtor.Digg
    {
        public class DiggModule : IModule
        {
    
            #region IModule 멤버
    
            public void Initialize()
            {
                //Shell.xaml의 ResultRegion 이름을 찾아서 DiggSearchResultView.xaml 이 등록된다
                regionManager.RegisterViewWithRegion("ResultRegion", typeof(NewsAggregtor.Digg.DiggSearchResultView));
            }
    
            #endregion
    
            private IRegionManager regionManager;
            public DiggModule(IRegionManager regionManager )
            {
                this.regionManager = regionManager;
            }
    
    
        }
    }
    

     

     

    NewsAggregtor.Shell.csproj 의 Shell.xaml 파일수정

    네임스페이스 추가

    xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"

     

    <UserControl xmlns:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"  x:Class="NewsAggregtor.Shell.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
        Width="400" Height="300">
        <Grid x:Name="LayoutRoot" Background="White">
        	<Grid.RowDefinitions>
        		<RowDefinition Height="0.197*"/>
        		<RowDefinition Height="0.803*"/>
        	</Grid.RowDefinitions>
            
            <ContentControl Regions:RegionManager.RegionName="searchRegion" Background="{x:Null}"/>
            <basics:TabControl Regions:RegionManager.RegionName="searchResult"></basics:TabControl>
        </Grid>
    </UserControl>

     

    모듈등록

    일단 Shell.xaml 페이지에

    xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"

    추가하고

    <ContentControl Regions:RegionManager.RegionName="searchRegion" Background="{x:Null}"/>
    <basics:TabControl Regions:RegionManager.RegionName="ResultRegion"></basics:TabControl>

    임의의 이름을 준다 나중에 모듈 올릴때 저 이름으로 찾아간다

     

    image

    잘 나타면 끗~

    Problem

    Typically, the user interface in a client application or Rich Internet Application (RIA) contains controls that display application domain data and allows users to modify and submit changes to the data. Defining application logic to control this process in the control's code-behind makes them complex and difficult to understand, maintain, evolve, test, and re-use.

    Forces

    Any of the following conditions justifies using the solution described in this pattern:

    • You want to maximize the code that can be tested with automation. (The user interface is hard to test automatically.)
    • You want to share code between pieces of the user interface (UI) that require the same underlying behavior.
    • You want to separate presentation and business logic from UI logic to make the code easier to understand and maintain.
    • You want to allow a user interface designer to easily create or modify the UI for your application; by doing this, developers can focus on the application's logic and structure.
    • The data that you want to display requires some form of conversion or adaptation before it can be displayed in the user interface.
    • The data that you want to display requires some form of validation before it can be updated by the user interface.

    Solution

    Separate the responsibilities for the visual display of the user interface and the presentation state and behavior into different classes named, respectively, the view and the presentation model. The view class manages the user interface controls and encapsulates any visual state or behavior that is specific to the UI. The presentation model class encapsulates presentation behavior and state and acts as a façade onto the underlying model. The view acts as an observer of the Presentation Model, and the Presentation Model acts as an observer of the Model. Figure 1 provides a logical view of the Presentation Model pattern.

    Dd458863.PresentModelFig1(en-us,MSDN.10).png

    Figure 1
    Presentation Model pattern logical view

    The presentation model should be designed to provide a public interface that can be easily consumed by a view, thereby reducing or eliminating the need for any complex code within the view for it to be able to interact cleanly with the presentation model. Specifically, the presentation model should be designed to support data binding, commands, and data templates.

    Data Binding

    By correctly designing the presentation model, developers can leverage the powerful data-binding capabilities provided by Windows Presentation Foundation (WPF) and Silverlight. With data binding, controls that are bound to application data automatically reflect changes when the underlying data changes its value. Similarly, data binding can automatically update the underlying data when the user modifies it in the user interface, such as if the user edits the value in a TextBox element, the underlying data value is automatically updated to reflect that change. In WPF and Silverlight, any dependency property of a control can be bound to a property on the presentation model.

    To support data binding, the presentation model should implement the INotifyPropertyChanged interface. Similarly, any objects provided to the view through properties should support the INotifyPropertyChanged or INotifyCollectionChanged interfaces. Implementing these interfaces allows the data binding mechanism to monitor the presentation model for changes so that it can automatically update the UI. The presentation model is typically set as the data context for the view so that the binding expressions defined in the view resolve to the corresponding properties on the presentation model.

    Dd458863.note(en-us,MSDN.10).gifNote:

    For more information about data binding in WPF, see Data Binding on MSDN. For data binding in Silverlight, see Data Binding on MSDN.

    Commands

    Commands in WPF and Silverlight represent actions that the user can perform through the user interface, such as the user submitting the current order by clicking the Submit button or menu item. Commands separate the visual representation of an available action with the actual code that implements that action.

    Commands allow the user interface to interact with the application's functionality in a declarative and automatic way without requiring any complex event handling code in the view's code-behind file. Interaction between the UI and the command is two-way. The command can be invoked as the user interacts with the UI, and the UI can be automatically updated as the underlying command becomes enabled or disabled.

    WPF controls can be easily associated with a command through the Command property. The control will automatically invoke the target command when the user interacts with that control. Silverlight controls can use the Click.Command attached behavior that the Composite Application Library provides to achieve the same behavior for any control that derives from ButtonBase. Other control events can easily be supported by creating a suitable attached behavior for it. For more information, see "Extending Command Support" in the Commands technical concept.

    The presentation model should encapsulate the implementation logic for commands so that it can be unit tested and more easily maintained. The presentation model should make commands available to the view by exposing them as ICommand valued properties. The Composite Application Library provides the DelegateCommand and CompositeCommand classes to make this easy to do. For more information, see the Commands technical concept.

    Dd458863.note(en-us,MSDN.10).gifNote:

    For more information about commands in WPF, see Commanding Overview on MSDN.

    Data Templates

    By using data templates, a visual designer can easily define how an object will be rendered in the user interface. A data template declares user interface controls that will be data bound at run time to the underlying object. The designer can dramatically modify or change the visual representation of an object without changing the underlying object.

    In WPF, you can specify the data template for an object type at the application level—WPF automatically applies the data template for any objects of that type that are displayed in the UI. In Silverlight, you have to explicitly specify the data template for an object within the control that is to display it.

    When you implement the Presentation Model pattern in a WPF or Silverlight application, you can define its view as a data template. Data templates are flexible and lightweight. UI designer can use them to easily define the visual representation of a presentation model without requiring any complex code. Data templates are ideally suited for views that do not require any UI logic (code-behind).

    For more information about data templates, see Data Templating Overview.

    Dd458863.note(en-us,MSDN.10).gifNote:

    A variant of the Presentation Model pattern named Model-View-ViewModel is commonly used in WPF and Silverlight applications. For more information, see WPF Apps With The Model-View-ViewModel Design Pattern in MSDN magazine.

    Example

    To see an example implementation of the Presentation Model pattern, see the files WatchListPresentationModel.cs, WatchListView.xaml, and WatchListService.cs in the Stock Trader Reference Implementation (these files are located in the WatchList folder of the StockTraderRI.Modules.Watch project).

    Liabilities

    The Presentation Model pattern has the following liabilities:

    • There are more solution elements to manage.
    • You need a way to synchronize the view with the presentation model. Typically, this is done through data binding.
    • The model is not aware of the presentation model. Therefore, if the model is changed by any component other than the presentation model, the presentation model must be notified. Typically, notification is implemented with the Observer pattern. For more information about the Observer pattern, see Exploring the Observer Design Pattern.

    Related Patterns

    The following patterns are related to the Separated Presentation pattern:

    • Supervising Presenter. This pattern is similar to the Presentation Model pattern and is suitable for situations in which the view can be directly bound to the model. The presenter coordinates the interaction between the view and the model by interpreting user gestures into actions against the model and changes in the model into user interface actions.

    More Information

    For more information about the Presentation Model pattern, see the following:

    For more information about software design patterns applied in the Composite Application Library and Stock Trader Reference Implementation, see Patterns in the Composite Application Library.

     

     

    출처 : http://msdn.microsoft.com/en-us/library/dd458863.aspx

    간단한 모듈등록하기

    실버라이트 프로젝트

    image

     

    이 프로젝트에서는 추가로

    image

    DLL을 추가해야합니다.

     

    Shell.xaml 는 맨처음 실행되는 페이지 입니다.

    <UserControl x:Class="HelloWorld.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
                 Width="400" Height="300">
        <ItemsControl Name="MainRegion" Regions:RegionManager.RegionName="MainRegion"/>
    </UserControl>

     

    Bootstrapper.cs

    using System.Windows;
    using Microsoft.Practices.Composite.Modularity;
    using Microsoft.Practices.Composite.UnityExtensions;
    
    namespace HelloWorld
    {
        public class Bootstrapper : UnityBootstrapper
        {
            protected override DependencyObject CreateShell()
            {
                Shell shell = Container.Resolve<Shell>();
                Application.Current.RootVisual = shell;
                return shell;
            }
    
            protected override IModuleCatalog GetModuleCatalog()
            {
                ModuleCatalog catalog = new ModuleCatalog()
                .AddModule(typeof(HelloWorldModule.HelloWorldModule));
                return catalog;
            }
        }
    }
    

    웹프로젝트

    image

    실버라이트 실행하는 웹페이지(이프로젝트는 크게 의미없습니다 )

     

    모듈 프로젝트 CALSilverlightModule.csproj

    image

    모듈 프로젝트는 (추가로 Microsoft.Practices.Composite 참조해야합니다).

     

    모듈프로젝트에서 아래의 코드를 삽입합니다.

    HelloWorldModule.cs

    using Microsoft.Practices.Composite.Modularity;
    using Microsoft.Practices.Composite.Regions;
    
    namespace HelloWorldModule
    {
        public class HelloWorldModule : IModule
        {
            private readonly IRegionManager regionManager;
    
            public HelloWorldModule(IRegionManager regionManager)
            {
                this.regionManager = regionManager;
            }
    
            public void Initialize()
            {
                regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.HelloWorldView));
            }
    
        }
    }
    

    HelloWorldView.xaml

    <UserControl x:Class="HelloWorldModule.Views.HelloWorldView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
        <Grid x:Name="LayoutRoot" Background="White">
                <TextBlock Text="Hello World" Foreground="Green" 
    HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" 
    FontWeight="Bold"></TextBlock>
        </Grid>
    </UserControl>

    http://www.codeplex.com/Silverlight

     

    What is the Silverlight Toolkit?

    The Silverlight Toolkit is a collection of Silverlight controls, components and utilities made available outside the normal Silverlight release cycle. It adds new functionality quickly for designers and developers, and provides the community an efficient way to help shape product development by contributing ideas and bug reports. It includes full source code, unit tests, samples and documentation for 16 new controls covering charting, styling, layout, and user input.

    Get Started

     

     

    Deep Zoom Composer

    Overview


    We are pleased to present a technology preview of Deep Zoom Composer, a tool to allow the preparation of images for use with the Deep Zoom feature currently being previewed in Silverlight 2. The new Deep Zoom technology in Silverlight allows users to see images on the Web like they never have before. The smooth in-place zooming and panning that Deep Zoom allows is a true advancement and raises the bar on what image viewing should be. High resolution images need to be prepared for use with Deep Zoom and this tool allows the user to create Deep Zoom composition files that control the zooming experience and then export all the necessary files for deployment with Silverlight 2.

    Prism: patterns & practices Composite Application Guidance for WPF and Silverlight site

    PrismV2StockTraderRIShell.png
    Overview

    The Composite Client Application Guidance is designed to help you more easily build modular Windows Presentation Foundation (WPF) and Silverlight client applications. These types of applications typically feature multiple screens, rich, flexible user interaction and data visualization, and role-determined behavior. They are "built to last" and "built for change." This means that the application's expected lifetime is measured in years and that it will change in response to new, unforeseen requirements. This application may start small and over time evolve into a composite client—composite applications use loosely coupled, independently evolvable pieces that work together in the overall application. Applications that do not demand these features and characteristics may not benefit from the Composite Application Guidance.
    The guidance includes a reference implementation, reusable library code (called the Composite Application Library), documentation, QuickStarts, and Hands-On Labs.

     

     

     

    http://www.codeplex.com/CompositeWPF

     

     

    Video How to: Create a C# WPF Application


    Authors: Kathleen McGrath, Harry Miller, Jo Molnar, Microsoft Corporation

    Applies to: Microsoft Visual C# 2008 Express Edition

    Length: 00:05:35 | Size: 13.8 MB | Type: WMV file

    Watch the video

    Download the video and transcript

    Read the step-by-step article

    Video Summary

    Creating a WPF application is similar to creating a Windows Forms application in that you can drag controls from the Toolbox to the design surface and then write code to handle the events of the controls. You can create WPF applications that are more graphically appealing through the use of Extensible Application Markup Language (XAML). In addition to having a designer, Properties window, and Toolbox, the IDE in WPF projects has a window that contains XAML.

    This video shows you how to create your own Ink application, which enables you to draw pictures. The following tasks are included in the process:

    • How to create a WPF application.

    • How to switch between Code view and Design view.

    • How to use the XAML editor.

    • How to add WPF controls to the WPF application.

    • How to create event handlers for WPF controls.

    The Visual C# Help includes the code and the steps that are demonstrated in this video. See How to: Create a C# WPF Application.

    Additional Video Resources

    Video How Tos

    Visual C# Videos

    Video How to: Create a C# Console Application

    Video How to: Create a C# Windows Forms Application

    Video How to: Creating a Drawing Application by Using WPF

    Other Videos

    Additional Help Resources

    + Recent posts