다음을 통해 공유


연습: RIA Services 둘러보기

이 연습에서는 WCF RIA Services의 다양한 기능에 대해 간략하게 설명합니다. 이 연습에서는 AdventureWorks OLTP 샘플 데이터베이스의 테이블에서 데이터를 검색하는 RIA Services 응용 프로그램을 만듭니다. 먼저 LoadOperation을 지정하여 데이터를 검색한 다음 DomainDataSource 컨트롤을 사용하여 해당 데이터를 검색합니다. 데이터 프레젠테이션 컨트롤의 정렬, 필터링 및 페이징을 지정하고 DataForm 컨트롤을 추가하여 데이터의 상세 뷰를 제공합니다. 또한 유효성 검사 규칙을 필드에 적용하고 사용자가 데이터 값을 편집할 수 있도록 하며, 도메인 작업에 대한 액세스를 인증된 사용자로만 제한합니다. 마지막으로 관련된 두 테이블 간의 연결을 정의하고 관련 데이터를 표시합니다.

Tip팁:
보다 기본적인 RIA Services 솔루션을 만들어 시작하기 위한 간단한 연습은 연습: RIA Services 솔루션 만들기 또는 연습: Silverlight 비즈니스 응용 프로그램 템플릿 사용을 참조하십시오.

필수 구성 요소

WCF RIA Services 설명서에서 제공하는 이 연습 및 다른 연습을 실행하려면 WCF RIA Services 및 WCF RIA Services 도구 키트 외에도 Visual Studio 2010, Silverlight Developer 런타임 및 SDK 등의 몇 가지 필수 구성 요소 프로그램을 올바르게 설치하고 구성해야 합니다. 또한 SQL Server 2008 R2 Express with Advanced Services를 설치하고 구성해야 하며 AdventureWorks OLTP 및 LT 데이터베이스를 설치해야 합니다.

이러한 각 사전 요구 사항을 충족하기 위한 자세한 지침은 WCF RIA Services의 사전 요구 사항 노드의 항목에서 제공합니다. 이 RIA Services 연습을 수행할 때 발생할 수 있는 문제를 최소화하려면 이 연습을 진행하기 전에 여기서 제공하는 지침을 따르십시오.

솔루션 만들기 및 설정

이 단원에서는 솔루션을 만들고 설정합니다.

새 WCF RIA Services 응용 프로그램을 만들려면

  1. Visual Studio 2010에서 파일, 새로 만들기, 프로젝트를 차례로 선택하여 새 RIA Services 프로젝트를 만듭니다.

    새 프로젝트 대화 상자가 나타납니다.

  2. 설치된 템플릿 창에서 Visual Basic 또는 Visual C# 노드를 확장하고 Silverlight 범주를 선택합니다.

  3. Silverlight 비즈니스 응용 프로그램 템플릿을 선택하고 이 응용 프로그램의 이름을 HRApp로 지정합니다.

    RIA_HRAppStart

  4. 확인을 클릭합니다.

    만들어진 솔루션의 구조를 확인합니다.

    • 솔루션은 HRApp라는 Silverlight 클라이언트 프로젝트와 HRApp.Web이라는 ASP.NET 웹 응용 프로그램 서버 프로젝트로 구성됩니다.

    • 기본 솔루션에는 탐색, 사용자 로그인 및 로그아웃, 새 사용자 등록 등, 자동으로 구현된 다양한 기능이 포함되어 있습니다.

    RIA_HRAppStructure

  5. 응용 프로그램을 빌드하고 실행(F5)한 다음 기본 구현을 탐색합니다.

  6. 웹 브라우저를 닫습니다.

응용 프로그램을 설정하려면

  1. 솔루션 탐색기의 클라이언트 프로젝트에서 MainPage.xaml을 엽니다.

  2. XAML 뷰에서 ApplicationNameTextBlock이라는 TextBlock을 찾습니다.

    다음 태그에 표시된 대로 응용 프로그램 이름이 리소스에서 검색된 것을 확인할 수 있습니다.

    <TextBlock x:Name="ApplicationNameTextBlock" Style="{StaticResource ApplicationNameStyle}" 
                       Text="{Binding ApplicationStrings.ApplicationName, Source={StaticResource ResourceWrapper}}"/>
    
  3. 솔루션 탐색기에서 Assets 폴더를 확장한 다음 Resources 폴더를 확장합니다.

  4. ApplicationStrings.resx 파일을 엽니다.

  5. ApplicationName 리소스를 HR Application으로 변경합니다.

  6. ApplicationStrings.resx 파일을 저장하고 닫습니다.

  7. 솔루션 탐색기에서 Views 폴더를 마우스 오른쪽 단추로 클릭하고 추가를 클릭한 다음 새 항목을 클릭합니다.

    새 항목 추가 대화 상자가 표시됩니다.

  8. 설치된 템플릿Silverlight 범주에서 Silverlight 페이지 템플릿을 선택하고 EmployeeList.xaml로 이름을 지정합니다.

    RIA_HRAppAddPage

  9. 추가를 클릭합니다.

  10. 자동으로 열리지 않는 경우 EmployeeList.xaml을 엽니다.

  11. 다음 XAML을 <Grid> 태그 사이에 추가합니다.

    <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource 
      PageScrollViewerStyle}" >
        <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">
    
            <TextBlock Text="Employee List" Style="{StaticResource HeaderTextStyle}"/>
    
        </StackPanel>
    </ScrollViewer>
    
  12. EmployeeList.xaml 파일을 저장합니다.

  13. MainPage.xaml을 엽니다.

  14. 다음 XAML을 기존의 두 하이퍼링크 단추 사이에 추가하여 페이지 맨 위에 새 하이퍼링크 단추를 추가합니다.

    <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" NavigateUri="/EmployeeList" TargetName="ContentFrame" Content="Employee List"/>
    
    <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
    
  15. 응용 프로그램을 실행하고 페이지의 오른쪽 위 모퉁이에 있는 링크과 정보 링크 사이에 새 직원 목록 링크가 표시되는 것을 확인합니다. 이 링크를 클릭하여 페이지 본문에 “직원 목록”을 표시합니다.

    RIA_HRAppPageView

데이터 표시

이 단원에서는 AdventureWorks 샘플 데이터베이스의 테이블에 대한 ADO.NET 엔터티 데이터 모델을 만듭니다. 그런 다음 엔터티를 노출하는 도메인 서비스를 만들고 클라이언트 프로젝트에서 해당 데이터를 표시합니다.

데이터 소스를 추가하려면

  1. 솔루션 탐색기에서 HRApp.Web 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가를 클릭한 다음 새 항목을 클릭합니다.

    새 항목 추가 대화 상자가 표시됩니다.

  2. 데이터 범주에서 ADO.NET 엔터티 데이터 모델 템플릿을 선택합니다.

    RIA_HRAppAddEntity

  3. 이름을 AdventureWorks.edmx로 변경하고 추가를 클릭합니다.

    엔터티 데이터 모델 마법사가 열립니다.

  4. 모델 콘텐츠 선택 페이지에서 데이터베이스에서 생성을 클릭하고 다음을 클릭합니다.

  5. 데이터 연결 선택 페이지에서 AdventureWorks 데이터베이스에 대한 연결을 만듭니다.

  6. 엔터티 연결 설정의 이름을 AdventureWorks_DataEntities로 지정하고 다음을 클릭합니다.

  7. 데이터베이스 개체 선택 페이지에서 테이블 노드를 확장합니다.

  8. Employee, PurchaseOrderDetailPurchaseOrderHeader 테이블 옆에 확인 표시를 추가합니다.

  9. 모델 네임스페이스의 이름을 AdventureWorks_DataModel로 지정한 다음 마침을 클릭합니다.

    엔터티 데이터 모델이 디자이너에 나타납니다.

  10. 솔루션을 빌드합니다.

도메인 서비스 개체와 데이터에 대한 쿼리를 추가하려면

  1. 솔루션 탐색기에서 HRApp.Web 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가를 클릭한 다음 새 항목을 클릭합니다.

    새 항목 추가 대화 상자가 표시됩니다.

  2. 범주에서 도메인 서비스 클래스 템플릿을 선택합니다.

    RIA_HRAppAddService

  3. 새 항목의 이름을 OrganizationService로 지정합니다.

  4. 추가를 클릭합니다.

  5. 새 도메인 서비스 클래스 추가 대화 상자의 엔터티 목록에서 Employee, PurchaseOrderDetailPurchaseOrderHeader를 선택하고 각 엔터티에 대해 편집 사용을 선택합니다.

  6. 클라이언트 액세스 사용메타데이터에 대한 연결된 클래스 생성 확인란이 선택되어 있는지 확인합니다.

  7. 확인을 클릭합니다.

    OrganizationService.cs/vb 및 OrganizationService.metadata.cs/vb 파일이 프로젝트에 추가됩니다.

  8. OrganizationService.cs/vb 파일을 엽니다.

    쿼리, 삽입, 업데이트 및 삭제 메서드가 각 엔터티에 대해 만들어진 것을 확인할 수 있습니다. 쿼리 메서드는 엔터티에 대해 항상 만들어집니다. 삽입, 업데이트 및 삭제 메서드는 편집 사용이 선택되어 있기 때문에 추가되었습니다.

  9. 생성된 코드를 다음 코드로 바꾸어 EmployeeID별로 정렬된 직원을 반환하도록 GetEmployees() 쿼리 메서드를 사용자 지정합니다.

    Public Function GetEmployees() As IQueryable(Of Employee)
        Return Me.ObjectContext.Employees.OrderBy(Function(e) e.EmployeeID)
    End Function
    
    public IQueryable<Employee> GetEmployees()
    {
        return this.ObjectContext.Employees.OrderBy(e => e.EmployeeID);
    }
    
  10. 솔루션을 빌드합니다.

    솔루션을 빌드하면 클라이언트 프로젝트에서 도메인 컨텍스트 및 엔터티가 생성됩니다.

  11. EmployeeList.xaml을 엽니다.

  12. 도구 상자에서 DataGrid 컨트롤을 디자인 뷰의 TextBlock 컨트롤 바로 뒤로 끌어 옵니다.

    DataGrid를 디자인 뷰로 끌어 오면 System.Windows.Controls.Data 어셈블리에 대한 참조가 추가되고 sdk 접두사가 Page 요소에 추가됩니다.

  13. Height 및 Width 속성을 제거하고 읽기 전용으로 설정한 후 열을 자동으로 생성하도록 설정하고 최소 높이를 설정하여 DataGrid 컨트롤의 기본값을 변경합니다.

    <sdk:DataGrid AutoGenerateColumns="True" IsReadOnly="True" Name="dataGrid1" MinHeight="100" />
    
  14. EmployeeList.xaml을 저장합니다.

  15. EmployeeList.xaml.cs/vb를 엽니다.

  16. 다음 using 또는 Imports 문을 추가합니다.

    Imports System.ServiceModel.DomainServices.Client
    
    using HRApp.Web;
    using System.ServiceModel.DomainServices.Client;
    
  17. 다음 코드를 EmployeeList.xaml.cs/vb에 추가하여 OrganizationContext 클래스를 인스턴스화하고 직원 데이터를 로드합니다.

    OrganizationContext 클래스가 서버 프로젝트의 OrganizationService 클래스를 기반으로 클라이언트 프로젝트에서 자동으로 생성됩니다.

    Partial Public Class EmployeeList
        Inherits Page
    
        Dim _OrganizationContext As New OrganizationContext
        Public Sub New()
            InitializeComponent()
            Me.dataGrid1.ItemsSource = _OrganizationContext.Employees
            _OrganizationContext.Load(_OrganizationContext.GetEmployeesQuery())
        End Sub
    
        'Executes when the user navigates to this page.
        Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)
    
        End Sub
    End Class
    
    public partial class EmployeeList : Page
    {
        OrganizationContext _OrganizationContext = new OrganizationContext();
        public EmployeeList()
        {
            InitializeComponent();
            this.dataGrid1.ItemsSource = _OrganizationContext.Employees;
            _OrganizationContext.Load(_OrganizationContext.GetEmployeesQuery());
        }
    
        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }
    }
    
  18. 응용 프로그램을 실행합니다.

  19. Employee List 링크를 클릭하여 DataGrid를 표시합니다.

    RIA_HRAppDataGrid

사용자 지정 쿼리를 추가하려면

  1. HRApp.Web 프로젝트에서 OrganizationService.cs/vb를 엽니다.

  2. 다음 코드를 클래스 본문에 추가하여 GetSalariedEmployees라는 새 메서드를 추가합니다.

    Public Function GetSalariedEmployees() As IQueryable(Of Employee)
        Return Me.ObjectContext.Employees.Where(Function(e) e.SalariedFlag = True).OrderBy(Function(e) e.EmployeeID)
    End Function
    
    public IQueryable<Employee> GetSalariedEmployees()
    {
        return this.ObjectContext.Employees.Where(e => e.SalariedFlag == true).OrderBy(e => e.EmployeeID);
    }
    
  3. 솔루션을 빌드합니다.

  4. 클라이언트 프로젝트에서 EmployeeList.xaml.cs/vb를 엽니다.

  5. 생성자에서 GetEmployeesQuery() 호출을 GetSalariedEmployeesQuery() 호출로 바꿉니다.

    _OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery())
    
    _OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery());
    
  6. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

    표시된 모든 직원의 SalariedFlag 값이 선택되어 있는 것을 확인할 수 있습니다. EmployeeID가 1, 2 및 4인 직원은 급여가 지급되지 않기 때문에 목록에 더 이상 표시되지 않습니다.

    RIA_HRAppFilteredDataGrid

도메인 데이터 소스를 추가하려면

  1. EmployeeList.xaml을 엽니다.

  2. 도구 상자에서 DomainDataSource 컨트롤을 디자인 뷰의 DataGrid 바로 앞으로 끌어 옵니다. DomainDataSource는 컨트롤 목록의 아래쪽에 나타날 수 있습니다.

    Tip팁:
    DomainDataSource 컨트롤이 도구 상자에 없으면 도구 상자를 마우스 오른쪽 단추로 클릭하고 항목 선택을 클릭합니다. Silverlight 구성 요소 탭 아래에서 DomainDataSource를 선택하고 확인을 클릭합니다.

    DomainDataSource 컨트롤을 디자인 뷰로 끌어 오면 riaControls 접두사가 있는 참조가 Page 요소에서 System.Windows.Controls 네임스페이스에 대해 만들어집니다. 또한 데이터 소스 아이콘이 디자인 뷰의 왼쪽 아래 모퉁이에 표시됩니다.

  3. C# 솔루션의 경우 다음 네임스페이스 선언을 XAML 파일에 추가합니다.

    xmlns:ds="clr-namespace:HRApp.Web"
    
  4. Visual Basic 솔루션의 경우 다음 네임스페이스 선언을 XAML 파일에 추가합니다.

    xmlns:ds="clr-namespace:HRApp"
    
  5. 기존 XAML을 다음 XAML로 바꿔서 DomainDataSource 컨트롤의 이름을 employeeDataSource로 지정하고 LoadSize, AutoLoad 및 쿼리 메서드를 설정합니다.

    <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
    </riaControls:DomainDataSource>
    
  6. 다음 XAML을 추가하여 DomainDataSourceDomainContext를 설정합니다.

    <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
        <riaControls:DomainDataSource.DomainContext>
            <ds:OrganizationContext/>
        </riaControls:DomainDataSource.DomainContext>
    </riaControls:DomainDataSource>
    
  7. DataGrid를 다음 XAML로 바꿉니다.

    <sdk:DataGrid AutoGenerateColumns="True" IsReadOnly="True" Name="dataGrid1" MinHeight="100" Height="Auto" ItemsSource="{Binding Data, ElementName=employeeDataSource}" />
    
  8. EmployeeList.xaml.cs/vb를 엽니다.

  9. 생성자에서 OrganizationContext 인스턴스를 인스턴스화하는 코드, GetSalariedEmployeesQuery() 호출, DataGrid 컨트롤의 ItemsSource 속성을 설정하는 코드를 제거하거나 주석으로 처리합니다.

    DomainDataSource가 이 작업을 자동으로 수행하므로 데이터를 더 이상 명시적으로 로드할 필요가 없습니다.

    'Dim _OrganizationContext As New OrganizationContext
    Public Sub New()
        InitializeComponent()
        'Me.dataGrid1.ItemsSource = _OrganizationContext.Employees
        '_OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery())
    
    End Sub
    
    //OrganizationContext _OrganizationContext = new OrganizationContext();
    public EmployeeList()
    {
        InitializeComponent();
        //this.dataGrid1.ItemsSource = _OrganizationContext.Employees;
        //_OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery());
    }
    
  10. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

    응용 프로그램이 이전과 동일하게 작동합니다.

정렬, 필터링 및 페이징을 데이터 소스에 추가하려면

  1. EmployeeList.xaml을 엽니다.

  2. DomainDataSource에서 다음 SortDescriptors를 추가하여 DataGrid에서 데이터가 정렬되는 방법을 지정합니다.

    이 XAML에서는 VacationHours 열을 오름차순으로 정렬하는 방법을 보여 줍니다.

    <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
        <riaControls:DomainDataSource.DomainContext>
            <ds:OrganizationContext/>
        </riaControls:DomainDataSource.DomainContext>
        <riaControls:DomainDataSource.SortDescriptors>
            <riaControls:SortDescriptor PropertyPath="VacationHours" Direction="Ascending" />
        </riaControls:DomainDataSource.SortDescriptors>
    </riaControls:DomainDataSource>
    
  3. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

    데이터가 VacationHours별로 정렬되며 열 머리글을 클릭하여 정렬 방향을 변경할 수 있습니다.

  4. EmployeeList.xaml을 엽니다.

  5. 사용자가 값을 제공하여 반환되는 레코드를 필터링할 수 있도록 하려면 다음 XAML을 DataGrid 앞에 추가합니다.

    이 XAML에서는 사용자가 값을 입력할 수 있도록 TextBox 컨트롤을 추가합니다.

    <StackPanel Orientation="Horizontal" 
      HorizontalAlignment="Left">
        <TextBlock VerticalAlignment="Center" 
        Text="Min Vacation Hours Filter" />
        <TextBox x:Name="vacationHoursText" Width="75" 
      FontSize="11" Margin="4" Text="0"/>
    </StackPanel>
    
  6. DomainDataSource에서 이전 단계에서 추가한 TextBox 컨트롤에 바인딩된 필터 설명자를 추가합니다.

    <riaControls:DomainDataSource.FilterDescriptors>
        <riaControls:FilterDescriptor 
             PropertyPath="VacationHours" 
             Operator="IsGreaterThanOrEqualTo"
             IgnoredValue=""
             Value="{Binding ElementName=vacationHoursText, Path=Text}"  >
        </riaControls:FilterDescriptor>
    </riaControls:DomainDataSource.FilterDescriptors>
    
  7. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

  8. 최소 휴가 시간 필터 텍스트 상자에 70을 입력합니다.

    표시되는 직원의 VacationHours가 70보다 크거나 같은 것을 확인할 수 있습니다.

    RIA_HRAppVacationFilter

  9. EmployeeList.xaml을 엽니다.

  10. 도구 상자에서 DataPager 컨트롤을 DataGrid 바로 아래로 끌어 옵니다.

  11. 다음 XAML과 같이 페이지 크기를 5로 설정하고 소스를 설정합니다.

    <sdk:DataPager PageSize="5" Source="{Binding Data, ElementName=employeeDataSource}" HorizontalAlignment="Left" />
    
  12. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

    DataGrid 아래에 페이지 및 페이저 컨트롤당 필터링된 데이터의 행이 5개만 표시됩니다.

    RIA_HRAppPagedData

마스터/자세히 보기 만들기

이 단원에서는 Silverlight Toolkit에서 DataForm 컨트롤을 사용하여 데이터의 상세 뷰를 제공합니다. 기본적으로 Silverlight 비즈니스 응용 프로그램 프로젝트 템플릿의 Libs 폴더에는 System.Windows.Controls.Data.DataForm.Toolkit.dll 이진 파일이 포함되어 있습니다.

DataForm을 추가하려면

  1. EmployeeList.xaml을 엽니다.

  2. 다음 네임스페이스 선언을 추가합니다.

    xmlns:dataForm="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
    
  3. DataPager 컨트롤 뒤에 다음 XAML을 추가하여 DataForm 컨트롤을 추가합니다.

    이 XAML에서는 DataForm 특성을 설정하고 표시할 열을 지정합니다.

    <dataForm:DataForm x:Name="dataForm1" Header="Employee Information"
            AutoGenerateFields="False" HorizontalAlignment="Left"
            AutoEdit="False" AutoCommit="False" Width="400"
            CurrentItem="{Binding SelectedItem, ElementName=dataGrid1}" Margin="0,12,0,0">
        <dataForm:DataForm.EditTemplate>
            <DataTemplate>
                <StackPanel>
                    <dataForm:DataField Label="Employee ID">
                        <TextBox IsReadOnly="True" 
                  Text="{Binding EmployeeID, Mode=OneWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Login ID">
                        <TextBox Text="{Binding LoginID, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Hire Date">
                        <TextBox Text="{Binding HireDate, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Marital Status">
                        <TextBox Text="{Binding MaritalStatus, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Gender">
                        <TextBox Text="{Binding Gender, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Vacation Hours">
                        <TextBox Text="{Binding VacationHours, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Sick Leave Hours">
                        <TextBox Text="{Binding SickLeaveHours, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Active">
                        <CheckBox IsChecked="{Binding CurrentFlag, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                    </dataForm:DataField>
                </StackPanel>
            </DataTemplate>
        </dataForm:DataForm.EditTemplate>
    </dataForm:DataForm>
    
  4. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

    DataFormDataGrid에서 선택한 항목의 세부 정보가 표시됩니다.

    RIA_HRAppDataForm

데이터베이스 업데이트

새 도메인 서비스 클래스 대화 상자의 편집 사용 확인란을 선택하면 엔터티를 업데이트, 삽입 및 삭제하는 메서드가 도메인 서비스 계층에서 생성됩니다. 이 단원에서는 사용자가 이러한 작업을 실행할 수 있도록 직원 목록의 사용자 인터페이스에 편집 단추를 추가합니다.

레코드를 업데이트하려면

  1. EmployeeList.xaml 파일을 엽니다.

  2. DataForm 컨트롤 뒤에 다음 XAML을 추가하여 전송 단추를 추가합니다.

    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,12,0,0">
        <Button x:Name="submitButton" Width="75" Height="23"  
            Content="Submit" Margin="4,0,0,0" Click="submitButton_Click"/>
    </StackPanel>
    
  3. DomainDataSource 컨트롤에서 SubmittedChanges 이벤트에 대한 이벤트 처리기를 지정합니다.

    <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True" SubmittedChanges="employeeDataSource_SubmittedChanges">
    
  4. EmployeeList.xaml.cs/vb를 엽니다.

  5. 단추 클릭 이벤트에 대한 다음 이벤트 처리기를 추가합니다.

    사용자가 작업이 처리되는 동안 변경 사항을 다시 제출하지 못하도록 submitButton이 사용할 수 없도록 설정됩니다.

    Private Sub submitButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        submitButton.IsEnabled = False
        employeeDataSource.SubmitChanges()
    End Sub
    
    private void submitButton_Click(object sender, RoutedEventArgs e)
    {
        submitButton.IsEnabled = false;
        employeeDataSource.SubmitChanges();
    }
    
  6. 제출 작업이 성공적으로 완료되었는지 여부를 확인하고 submitButton을 사용하도록 설정하는 SubmittedChanges 이벤트에 대한 이벤트 처리기를 추가합니다.

    Private Sub employeeDataSource_SubmittedChanges(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SubmittedChangesEventArgs)
        If (e.HasError) Then
            MessageBox.Show(String.Format("Changes were not saved: {0}", e.Error.Message))
            e.MarkErrorAsHandled()
        End If
        submitButton.IsEnabled = True
    End Sub
    
    private void employeeDataSource_SubmittedChanges(object sender, SubmittedChangesEventArgs e)
    {
        if (e.HasError)
        {
            MessageBox.Show(string.Format("Changes were not saved: {0}", e.Error.Message));
            e.MarkErrorAsHandled();
        }
        submitButton.IsEnabled = true;
    }
    
  7. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

  8. 직원을 선택하고 데이터 폼의 오른쪽 위 모퉁이에서 연필 아이콘을 클릭하여 편집을 사용하도록 설정합니다.

    이제 편집 가능한 필드를 수정할 수 있습니다.

  9. 직원 데이터를 변경하고 확인을 클릭합니다.

  10. 전송 단추를 클릭하여 데이터를 저장합니다.

    전송 단추를 클릭하는 경우에만 변경 내용이 서버의 데이터베이스에 저장됩니다.

도메인 서비스에 사용자 지정 메서드를 추가하려면

  1. HRApp.Web 서버 프로젝트에서 OrganizationService.cs/vb 파일을 엽니다.

  2. ApproveSabbatical이라는 다음 사용자 지정 메서드를 추가합니다.

    Public Sub ApproveSabbatical(ByVal current As Employee)
        Me.ObjectContext.Employees.AttachAsModified(current)
        current.CurrentFlag = False
    End Sub
    
    public void ApproveSabbatical(Employee current)
    {
        // Start custom workflow here
        this.ObjectContext.Employees.AttachAsModified(current);
        current.CurrentFlag = false;
    }
    
  3. 솔루션을 빌드합니다.

  4. EmployeeList.xaml을 엽니다.

  5. 전송 단추 뒤에 다음 XAML을 추가하여 안식 기간 승인 단추를 추가합니다.

    <Button x:Name="approveSabbatical" Width="115" Height="23"  Content="Approve Sabbatical"  Margin="4,0,0,0" Click="approveSabbatical_Click"/>
    
  6. EmployeeList.xaml.cs/vb를 엽니다.

  7. ApproveSabbatical 도메인 작업을 호출하는 단추 클릭 이벤트에 대한 다음 이벤트 처리기를 추가합니다.

    Private Sub approveSabbatical_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Dim luckyEmployee As Employee
        luckyEmployee = dataGrid1.SelectedItem
        luckyEmployee.ApproveSabbatical()
        employeeDataSource.SubmitChanges()
    End Sub
    
    private void approveSabbatical_Click(object sender, RoutedEventArgs e)
    {
        Employee luckyEmployee = (Employee)(dataGrid1.SelectedItem);
        luckyEmployee.ApproveSabbatical();
        employeeDataSource.SubmitChanges();
    }
    
  8. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

  9. 안식 기간 승인 단추를 클릭하고 선택한 직원에 대한 CurrentFlag 확인란의 선택이 취소된 것을 확인합니다.

데이터 유효성 검사

DataForm 컨트롤은 DAL(데이터 액세스 계층)의 유효성 검사 오류를 표시할 수 있습니다. 예를 들어 VacationHours 필드에 정수가 아닌 값을 입력하면 유효성 검사 오류가 표시됩니다. 다음 그림에서는 유효성 검사 동작의 예를 보여 줍니다.

RIA_HRAppValidation

새 도메인 서비스 클래스 대화 상자에서 메타데이터에 대한 연결된 클래스 생성 확인란을 선택하면 메타데이터가 포함된 파일이 만들어집니다. 이 연습에서 메타데이터 파일의 이름은 OrganizationService.metadata.cs/vb로 지정됩니다. 이 단원에서는 이 파일에 유효성 검사 특성을 추가합니다. 유효성 검사 규칙은 클라이언트 및 서버 프로젝트에서 적용됩니다.

또한 새 직원 레코드를 데이터베이스에 추가할 수 있도록 하는 사용자 인터페이스도 만듭니다. 이전 단원에서 추가한 유효성 검사 규칙은 새 사용자 인터페이스에서 자동으로 적용됩니다.

기본 유효성 검사를 추가하려면

  1. HRApp.web 프로젝트에서 OrganizationService.metadata.cs/vb를 엽니다.

  2. GenderVacationHours 속성에 다음 특성을 추가합니다.

    <Required()> _
    Public Property Gender As String
    
    <Range(0, 70)> _
    Public Property VacationHours As Short
    
    [Required]
    public string Gender { get; set; }
    
    [Range(0, 70)]
    public short VacationHours { get; set; }
    
  3. 솔루션을 빌드합니다.

  4. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

  5. 직원을 선택하고 데이터 폼의 오른쪽 위 모퉁이에서 연필 아이콘을 클릭하여 편집을 사용하도록 설정합니다.

  6. 유효한 범위(0-70)에 들지 않는 값을 휴가 시간 필드에 입력하고 다른 컨트롤로 포커스를 이동합니다.

    휴가 시간에 대한 유효성 검사 오류가 표시됩니다.

    RIA_HRAppRangeValidation

  7. 성별 필드의 값을 삭제하고 다른 컨트롤로 포커스를 이동합니다.

    성별에 대한 유효성 검사 오류가 표시됩니다.

사용자 지정 유효성 검사를 추가하려면

  1. 솔루션 탐색기에서 HRApp.Web 프로젝트를 마우스 오른쪽 단추로 클릭하고 추가를 클릭한 다음 새 항목을 클릭합니다.

    새 항목 추가 대화 상자가 표시됩니다.

  2. 코드 범주에서 코드 파일 템플릿을 선택합니다.

  3. 새 항목의 이름을 OrganizationService.shared.cs 또는 OrganizationService.shared.vb로 지정합니다.

    .shared.cs 또는 .shared.vb로 끝나는 파일은 클라이언트 프로젝트와 서버 프로젝트에서 사용할 수 있습니다. 공유 파일을 사용하면 두 프로젝트에서 동일한 유효성 검사 규칙을 실행할 수 있습니다. 이후 단계에서 솔루션을 빌드한 후 클라이언트의 숨겨진 Generated_Code 폴더에 OrganizationService.shared.cs/vb 파일이 표시됩니다.

  4. 추가를 클릭합니다.

  5. Gender 속성에 할당된 값을 확인하는 사용자 지정된 유효성 검사 클래스를 만들려면 다음 코드를 공유 파일에 추가합니다.

    Imports System
    Imports System.ComponentModel.DataAnnotations
    
    Public Module GenderValidator
        Public Function IsGenderValid(ByVal gender As String, ByVal context As ValidationContext) As ValidationResult
            If gender = "M" OrElse gender = "m" OrElse gender = "F" OrElse gender = "f" Then
                Return ValidationResult.Success
            Else
                Return New ValidationResult("The Gender field only has two valid values 'M'/'F'", New String() {"Gender"})
            End If
        End Function
    End Module
    
    using System;
    using System.ComponentModel.DataAnnotations;
    
    namespace HRApp.Web
    {
        public static class GenderValidator
        {
            public static ValidationResult IsGenderValid(string gender, ValidationContext context)
            {
                if (gender == "M" || gender == "m" || gender == "F" || gender == "f")
                {
                    return ValidationResult.Success;
                }
                else
                {
                    return new ValidationResult("The Gender field only has two valid values 'M'/'F'", new string[] { "Gender" });
                }
            }
        }
    }
    
  6. OrganizationService.metadata.cs/vb를 엽니다.

  7. 다음 사용자 지정 유효성 검사 특성을 Gender 속성에 추가합니다.

    <Required()> _
    <CustomValidation(GetType(GenderValidator), "IsGenderValid")> _
    Public Property Gender As String
    
    [CustomValidation(typeof(HRApp.Web.GenderValidator), "IsGenderValid")]
    [Required]
    public string Gender { get; set; }
    
  8. 솔루션을 빌드합니다.

  9. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

  10. 직원을 선택하고 데이터 폼의 오른쪽 위 모퉁이에서 연필 아이콘을 클릭하여 편집을 사용하도록 설정합니다.

  11. M 또는 F가 아닌 값을 성별 필드에 입력하고 다른 컨트롤로 포커스를 이동합니다.

    사용자 지정 유효성 검사의 결과가 표시됩니다.

    RIA_HRAppCustomValidation

새 레코드 추가

이 단원에서는 사용자가 Employee 테이블에서 새 레코드를 만들 수 있도록 하는 폼을 추가합니다.

새 레코드를 추가하려면

  1. HRApp 프로젝트에서 새 항목을 추가합니다.

  2. Silverlight 범주에서 Silverlight 자식 창 템플릿을 선택합니다.

  3. 새 항목의 이름을 EmployeeRegistrationWindow.xaml로 지정합니다.

    RIA_HRAppAddChildWindow

  4. 추가를 클릭합니다.

  5. EmployeeRegistrationWindow.xaml.cs/vb를 엽니다.

  6. C#을 사용하는 경우 다음 using 문을 추가합니다.

    using HRApp.Web;
    
  7. 사용자 값을 사용하여 만들어진 새 Employee 엔터티에 대한 속성을 추가합니다.

    Public Property NewEmployee As Employee
    
    public Employee NewEmployee { get; set; }
    
  8. EmployeeRegistrationWindow.xaml을 엽니다.

  9. 다음 네임스페이스 선언을 EmployeeRegistrationWindow.xaml에 추가하여 이 창에서 DataForm 컨트롤을 사용합니다.

    xmlns:dataForm="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
    
  10. 다음 DataForm 컨트롤을 EmployeeRegistrationWindow.xaml에서 Cancel 단추 바로 앞에 추가합니다.

    <dataForm:DataForm x:Name="addEmployeeDataForm"   AutoGenerateFields="False" AutoCommit="True" AutoEdit="True" CommandButtonsVisibility="None">
        <dataForm:DataForm.EditTemplate>
            <DataTemplate>
                <StackPanel>
                    <dataForm:DataField Label="Login ID">
                        <TextBox Text="{Binding LoginID, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="National ID">
                        <TextBox Text="{Binding NationalIDNumber, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Title">
                        <TextBox Text="{Binding Title, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Marital Status">
                        <TextBox Text="{Binding MaritalStatus, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Gender">
                        <TextBox Text="{Binding Gender, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Salaried">
                        <CheckBox IsChecked="{Binding SalariedFlag, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Active">
                        <CheckBox IsChecked="{Binding CurrentFlag, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }" />
                    </dataForm:DataField>
                </StackPanel>
            </DataTemplate>
        </dataForm:DataForm.EditTemplate>
    </dataForm:DataForm>
    
  11. EmployeeRegistrationWindow.xaml.cs/vb를 엽니다.

  12. 다음 코드를 추가하여 새 Employee 인스턴스를 만들고 새 인스턴스 커밋이나 삽입 취소를 처리합니다.

    Partial Public Class EmployeeRegistrationWindow
        Inherits ChildWindow
    
        Public Sub New()
            InitializeComponent()
            NewEmployee = New Employee
            addEmployeeDataForm.CurrentItem = NewEmployee
            addEmployeeDataForm.BeginEdit()
        End Sub
    
        Public Property NewEmployee As Employee
    
        Private Sub OKButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles OKButton.Click
            Me.addEmployeeDataForm.CommitEdit()
            Me.DialogResult = True
        End Sub
    
        Private Sub CancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles CancelButton.Click
            NewEmployee = Nothing
            addEmployeeDataForm.CancelEdit()
            Me.DialogResult = False
        End Sub
    
    End Class
    
    public partial class EmployeeRegistrationWindow : ChildWindow
    {
        public EmployeeRegistrationWindow()
        {
            InitializeComponent();
            NewEmployee = new Employee();
            addEmployeeDataForm.CurrentItem = NewEmployee;
            addEmployeeDataForm.BeginEdit();    
        }
    
        public Employee NewEmployee { get; set; }
    
        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            addEmployeeDataForm.CommitEdit();
            this.DialogResult = true;
        }
    
        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            NewEmployee = null;
            addEmployeeDataForm.CancelEdit();
            this.DialogResult = false;
        }
    }
    
  13. EmployeeList.xaml을 엽니다.

  14. DataPagerDataForm 사이에 다음 XAML을 추가하여 addNewEmployee라는 단추를 만듭니다.

    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,12,0,0">
        <Button x:Name="addNewEmployee" Width="90" Height="23"  Content="Add Employee"  Margin="4,0,0,0" Click="addNewEmployee_Click"/>
    </StackPanel>
    
  15. EmployeeList.xaml.cs/vb를 엽니다.

  16. 다음 코드를 추가하여 단추 클릭 이벤트를 처리하고 EmployeeRegistrationWindow를 표시합니다.

    Private Sub addNewEmployee_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Dim addEmp As New EmployeeRegistrationWindow()
        AddHandler addEmp.Closed, AddressOf addEmp_Closed
        addEmp.Show()
    End Sub
    
    private void addNewEmployee_Click(object sender, RoutedEventArgs e)
    {
        EmployeeRegistrationWindow addEmp = new EmployeeRegistrationWindow();
        addEmp.Closed += new EventHandler(addEmp_Closed);
        addEmp.Show();
    }
    
  17. 다음 메서드를 추가하여 EmployeeRegistrationWindow에 대한 closed 이벤트를 처리합니다.

    Private Sub addEmp_Closed(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim emp As EmployeeRegistrationWindow = sender
        If Not emp.NewEmployee Is Nothing Then
            Dim _OrganizationContext As OrganizationContext = employeeDataSource.DomainContext
            _OrganizationContext.Employees.Add(emp.NewEmployee)
            employeeDataSource.SubmitChanges()
        End If
    End Sub
    
    void addEmp_Closed(object sender, EventArgs e)
    {
        EmployeeRegistrationWindow emp = (EmployeeRegistrationWindow)sender;
        if (emp.NewEmployee != null)
        {
            OrganizationContext _OrganizationContext = (OrganizationContext)(employeeDataSource.DomainContext);
            _OrganizationContext.Employees.Add(emp.NewEmployee);
            employeeDataSource.SubmitChanges();
        }
    }
    
  18. OrganizationService.cs/vb를 엽니다.

  19. 다음 코드를 추가하여 InsertEmployee 메서드를 수정합니다.

    Public Sub InsertEmployee(ByVal employee As Employee)
        employee.HireDate = DateTime.Now
        employee.ModifiedDate = DateTime.Now
        employee.VacationHours = 0
        employee.SickLeaveHours = 0
        employee.rowguid = Guid.NewGuid()
        employee.ContactID = 1001
        employee.BirthDate = New DateTime(1967, 3, 18)
    
        If ((employee.EntityState = EntityState.Detached) _
                    = False) Then
            Me.ObjectContext.ObjectStateManager.ChangeObjectState(employee, EntityState.Added)
        Else
            Me.ObjectContext.Employees.AddObject(employee)
        End If
    End Sub
    
    public void InsertEmployee(Employee employee)
    {
        employee.HireDate = DateTime.Now;
        employee.ModifiedDate = DateTime.Now;
        employee.VacationHours = 0;
        employee.SickLeaveHours = 0;
        employee.rowguid = Guid.NewGuid();
        employee.ContactID = 1001;
        employee.BirthDate = new DateTime(1967, 3, 18);
    
        if ((employee.EntityState != EntityState.Detached))
        {
            this.ObjectContext.ObjectStateManager.ChangeObjectState(employee, EntityState.Added);
        }
        else
        {
            this.ObjectContext.Employees.AddObject(employee);
        }
    }
    
  20. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

  21. 직원 추가 단추를 클릭합니다.

    EmployeeRegistrationWindow가 열립니다.

    RIA_Employee_Registration

  22. 이 창에서 데이터를 추가하고 유급 확인란을 선택합니다.

  23. 확인을 클릭합니다.

  24. 페이지를 새로 고치고 새 직원이 DataGrid에 표시되는지 확인합니다.

사용자 인증

이 단원에서는 ApproveSabbatical 메서드에 대한 액세스를 인증된 사용자로만 제한합니다.

인증을 추가하려면

  1. OrganizationService.cs/vb를 엽니다.

  2. RequiresAuthentication 특성을 ApproveSabbatical 메서드에 추가합니다.

    도메인 작업에 RequiresAuthentication 특성을 적용하면 인증된 사용자만 해당 작업을 호출할 수 있습니다. 익명 사용자가 안식 기간 승인 단추를 클릭하면 해당 작업이 실행되지 않습니다.

    <RequiresAuthentication()> _
    Public Sub ApproveSabbatical(ByVal current As Employee)
        Me.ObjectContext.Employees.AttachAsModified(current)
        current.CurrentFlag = False
    End Sub
    
    [RequiresAuthentication]
    public void ApproveSabbatical(Employee current)
    {
        // Start custom workflow here
        this.ObjectContext.Employees.AttachAsModified(current);
        current.CurrentFlag = false;
    }
    
  3. EmployeeList.xaml.cs/vb를 엽니다.

  4. 다음 using 또는 Imports 문을 추가합니다.

    Imports System.ServiceModel.DomainServices.Client.ApplicationServices
    Imports HRApp.LoginUI
    
    using System.ServiceModel.DomainServices.Client.ApplicationServices;
    using HRApp.LoginUI;
    
  5. approveSabbatical_Click 메서드를 수정하고 LoggedIn 처리기를 추가하여 사용자가 인증되었는지 여부를 확인합니다.

    Private Sub approveSabbatical_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        If WebContext.Current.User IsNot Nothing AndAlso WebContext.Current.User.IsAuthenticated Then
            Dim luckyEmployee As Employee = dataGrid1.SelectedItem
            luckyEmployee.ApproveSabbatical()
            employeeDataSource.SubmitChanges()
        Else
            AddHandler WebContext.Current.Authentication.LoggedIn, AddressOf Current_LoginCompleted
            Dim newWindow As New LoginRegistrationWindow
            newWindow.Show()
        End If
    End Sub
    
    Private Sub Current_LoginCompleted(ByVal sender As Object, ByVal e As AuthenticationEventArgs)
        Dim luckyEmployee As Employee = dataGrid1.SelectedItem
        luckyEmployee.ApproveSabbatical()
        employeeDataSource.SubmitChanges()
        RemoveHandler WebContext.Current.Authentication.LoggedIn, AddressOf Current_LoginCompleted
    End Sub
    
    private void approveSabbatical_Click(object sender, RoutedEventArgs e)
    {
        if (WebContext.Current.User.IsAuthenticated)
        {
            Employee luckyEmployee = (Employee)(dataGrid1.SelectedItem);
            luckyEmployee.ApproveSabbatical();
            employeeDataSource.SubmitChanges();
        }
        else
        {
            WebContext.Current.Authentication.LoggedIn += Authentication_LoggedIn;
            new LoginRegistrationWindow().Show();
        }
    }
    
    private void Authentication_LoggedIn(object sender, AuthenticationEventArgs e)
    {
        Employee luckyEmployee = (Employee)(dataGrid1.SelectedItem);
        luckyEmployee.ApproveSabbatical();
        employeeDataSource.SubmitChanges();
    
        WebContext.Current.Authentication.LoggedIn -= Authentication_LoggedIn;
    }
    
  6. 응용 프로그램을 실행하고 Employee List 링크를 클릭합니다.

  7. 직원 레코드를 선택하고 안식 기간 승인 단추를 클릭합니다.

    로그인 창으로 리디렉션됩니다.

  8. 지금 등록 링크를 클릭합니다.

  9. 새 계정을 만드는 데 필요한 필드를 완성합니다.

  10. 확인을 클릭합니다.

    이 계정을 사용하여 로그인되고 해당 이름이 탐색 링크 아래의 표시줄에 나타납니다.

관련 데이터 표시

RIA Services 를 사용하여 관련 테이블의 데이터로 쉽게 작업할 수 있습니다. 이 단원에서는 새 Silverlight 페이지를 추가하고 PurchaseOrderHeader 및 PurchaseOrderDetail 테이블의 데이터를 표시합니다. 관련 데이터가 함께 수정되도록 데이터 수정 작업을 사용자 지정할 수도 있습니다. 도메인 작업을 통해 관련 테이블의 데이터를 수정하는 예제는 구성 계층 구조를 참조하십시오.

관련 테이블의 데이터를 표시하려면

  1. HRApp 프로젝트에서 Views 폴더를 마우스 오른쪽 단추로 클릭하고 추가를 클릭한 다음 새 항목을 클릭합니다.

  2. PurchaseOrders.xaml이라는 새 Silverlight 페이지를 추가합니다.

  3. PurchaseOrders.xaml을 엽니다.

  4. 다음 XAML을 <Grid> 태그 사이에 추가합니다.

    <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource 
      PageScrollViewerStyle}" >
        <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">
    
            <TextBlock Text="Purchase Orders" Style="{StaticResource HeaderTextStyle}"/>
        </StackPanel>
    </ScrollViewer>
    
  5. MainPage.xaml을 엽니다.

  6. EmployeeList 링크 뒤에 다음 XAML을 추가하여 PurchaseOrders 페이지에 대한 링크를 포함합니다.

    <Rectangle x:Name="Divider3" Style="{StaticResource DividerStyle}"/>
    
    <HyperlinkButton x:Name="Link4" Style="{StaticResource LinkStyle}" NavigateUri="/PurchaseOrders" TargetName="ContentFrame" Content="Purchase Orders"/>
    
  7. OrganizationService.metadata.cs/vb를 엽니다.

  8. IncludeComposition 특성을 PurchaseOrderHeaderMetadata 클래스의 PurchaseOrderDetails 속성에 추가합니다.

    <Include()> _
    <Composition()> _
    Public Property PurchaseOrderDetails As EntityCollection(Of PurchaseOrderDetail)
    
    [Include]
    [Composition]
    public EntityCollection<PurchaseOrderDetail> PurchaseOrderDetails { get; set; }
    
  9. OrganizationService.cs/vb를 엽니다.

  10. PurchaseOrderDetails의 관련 레코드도 쿼리를 사용하여 검색되도록 GetPurchaseOrderHeaders 메서드를 변경합니다.

    Public Function GetPurchaseOrderHeaders() As IQueryable(Of PurchaseOrderHeader)
        Return Me.ObjectContext.PurchaseOrderHeaders.Include("PurchaseOrderDetails").OrderBy(Function(p) p.PurchaseOrderID)
    End Function
    
    public IQueryable<PurchaseOrderHeader> GetPurchaseOrderHeaders()
    {
        return this.ObjectContext.PurchaseOrderHeaders.Include("PurchaseOrderDetails").OrderBy(p => p.PurchaseOrderID);
    }
    
  11. PurchaseOrders.xaml을 엽니다.

  12. 데이터 메뉴에서 데이터 소스 표시를 클릭하여 데이터 소스 창을 엽니다.

  13. PurchaseOrders.xaml에 대한 PurchaseOrderHeader 노드를 디자인 화면으로 끌어 옵니다.

    RIA_Order_Header

    PurchaseOrderHeader 테이블의 열이 포함된 DataGrid가 나타납니다.

  14. 데이터 소스 창에서 PurchaseOrderHeader 노드를 확장합니다.

  15. PurchaseOrderHeader에 대한 PurchaseOrderHeader 노드 안에 있는 PurchaseOrderDetails 노드를 디자인 화면의 DataGrid 바로 아래로 끌어 옵니다.

    RIA_Order_Details

    PurchaseOrderDetails 테이블의 열이 포함된 DataGrid가 나타납니다.

  16. XAML 뷰에서 PurchaseOrderHeaderPurchaseOrderDetails에 대한 DataGrid 컨트롤을 찾습니다.

  17. 사용 가능한 너비를 채우도록 각 DataGrid에서 Width=”400” 속성을 제거합니다.

  18. 데이터에 레이블을 지정하기 위해 다음 TextBlock 컨트롤을 PurchaseOrderHeader DataGrid 앞에 추가합니다.

    <TextBlock Text="Order Headers"></TextBlock>
    
  19. 데이터에 레이블을 지정하기 위해 다음 TextBlock 컨트롤을 PurchaseOrderDetails DataGrid 앞에 추가합니다.

    <TextBlock Text="Order Details"></TextBlock>
    
  20. 검색된 레코드 수를 제한하기 위해 다음 필터 설명자를 DomainDataSource 컨트롤에 추가합니다.

    <riaControls:DomainDataSource.FilterDescriptors>
        <riaControls:FilterDescriptor PropertyPath="PurchaseOrderID" Operator="IsLessThan" Value="10"></riaControls:FilterDescriptor>
    </riaControls:DomainDataSource.FilterDescriptors>
    

    PurchaseOrders.xaml의 전체 XAML은 다음과 같습니다.

    <navigation:Page x:Class="HRApp.Views.PurchaseOrders" 
               xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
               xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
               xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
               xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
               mc:Ignorable="d"
               xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
               d:DesignWidth="640" d:DesignHeight="480"
               Title="PurchaseOrders Page" 
               xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices" 
               xmlns:my="clr-namespace:HRApp.Web" 
               xmlns:sdk="https://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
        <sdk:Page.Resources>
            <CollectionViewSource x:Key="purchaseOrderHeaderPurchaseOrderDetailsViewSource" Source="{Binding Path=Data.PurchaseOrderDetails, ElementName=purchaseOrderHeaderDomainDataSource}" />
        </sdk:Page.Resources>
        <Grid x:Name="LayoutRoot">
            <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource 
              PageScrollViewerStyle}" >
                <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">
    
                    <TextBlock Text="Purchase Orders" Style="{StaticResource HeaderTextStyle}"/>
                    <riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my:PurchaseOrderHeader, CreateList=true}" Height="0" LoadedData="purchaseOrderHeaderDomainDataSource_LoadedData_1" Name="purchaseOrderHeaderDomainDataSource" QueryName="GetPurchaseOrderHeadersQuery" Width="0">
                        <riaControls:DomainDataSource.DomainContext>
                            <my:OrganizationContext />
                        </riaControls:DomainDataSource.DomainContext>
                        <riaControls:DomainDataSource.FilterDescriptors>
                            <riaControls:FilterDescriptor PropertyPath="PurchaseOrderID" Operator="IsLessThan" Value="10"></riaControls:FilterDescriptor>
                        </riaControls:DomainDataSource.FilterDescriptors>
                    </riaControls:DomainDataSource>
                    <TextBlock Text="Order Headers"></TextBlock>
                    <sdk:DataGrid AutoGenerateColumns="False" Height="200" ItemsSource="{Binding ElementName=purchaseOrderHeaderDomainDataSource, Path=Data}" Name="purchaseOrderHeaderDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected">
                        <sdk:DataGrid.Columns>
                            <sdk:DataGridTextColumn x:Name="employeeIDColumn" Binding="{Binding Path=EmployeeID}" Header="Employee ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="freightColumn" Binding="{Binding Path=Freight}" Header="Freight" Width="SizeToHeader" />
                            <sdk:DataGridTemplateColumn x:Name="modifiedDateColumn" Header="Modified Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=ModifiedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=ModifiedDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTemplateColumn x:Name="orderDateColumn" Header="Order Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=OrderDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=OrderDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTextColumn x:Name="purchaseOrderIDColumn" Binding="{Binding Path=PurchaseOrderID, Mode=OneWay}" Header="Purchase Order ID" IsReadOnly="True" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="revisionNumberColumn" Binding="{Binding Path=RevisionNumber}" Header="Revision Number" Width="SizeToHeader" />
                            <sdk:DataGridTemplateColumn x:Name="shipDateColumn" Header="Ship Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=ShipDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=ShipDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTextColumn x:Name="shipMethodIDColumn" Binding="{Binding Path=ShipMethodID}" Header="Ship Method ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="statusColumn" Binding="{Binding Path=Status}" Header="Status" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="subTotalColumn" Binding="{Binding Path=SubTotal}" Header="Sub Total" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="taxAmtColumn" Binding="{Binding Path=TaxAmt}" Header="Tax Amt" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="totalDueColumn" Binding="{Binding Path=TotalDue}" Header="Total Due" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="vendorIDColumn" Binding="{Binding Path=VendorID}" Header="Vendor ID" Width="SizeToHeader" />
                        </sdk:DataGrid.Columns>
                    </sdk:DataGrid>
                    <TextBlock Text="Order Details"></TextBlock>
                    <sdk:DataGrid AutoGenerateColumns="False" Height="200" ItemsSource="{Binding Source={StaticResource purchaseOrderHeaderPurchaseOrderDetailsViewSource}}" Name="purchaseOrderDetailsDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected">
                        <sdk:DataGrid.Columns>
                            <sdk:DataGridTemplateColumn x:Name="dueDateColumn" Header="Due Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=DueDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=DueDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTextColumn x:Name="lineTotalColumn" Binding="{Binding Path=LineTotal}" Header="Line Total" Width="SizeToHeader" />
                            <sdk:DataGridTemplateColumn x:Name="modifiedDateColumn1" Header="Modified Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=ModifiedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=ModifiedDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTextColumn x:Name="orderQtyColumn" Binding="{Binding Path=OrderQty}" Header="Order Qty" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="productIDColumn" Binding="{Binding Path=ProductID}" Header="Product ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="purchaseOrderDetailIDColumn" Binding="{Binding Path=PurchaseOrderDetailID}" Header="Purchase Order Detail ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="purchaseOrderIDColumn1" Binding="{Binding Path=PurchaseOrderID}" Header="Purchase Order ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="receivedQtyColumn" Binding="{Binding Path=ReceivedQty}" Header="Received Qty" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="rejectedQtyColumn" Binding="{Binding Path=RejectedQty}" Header="Rejected Qty" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="stockedQtyColumn" Binding="{Binding Path=StockedQty}" Header="Stocked Qty" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="unitPriceColumn" Binding="{Binding Path=UnitPrice}" Header="Unit Price" Width="SizeToHeader" />
                        </sdk:DataGrid.Columns>
                    </sdk:DataGrid>
                </StackPanel>
            </ScrollViewer>
        </Grid>
    </navigation:Page>
    
  21. 응용 프로그램을 실행하고 구매 주문 링크를 클릭합니다.

  22. PurchaseOrderHeader DataGrid에서 여러 레코드를 선택합니다.

    관련된 PurchaseOrderDetail 레코드가 자동으로 표시되는 것을 확인할 수 있습니다.

    RIA_Details_and_Header

다음 단계

이 연습에서는 RIA Services 의 다양한 기능을 간략하게 살펴보았습니다. 특정 영역에 대해 자세히 알아보려면 이 설명서의 다른 연습을 참조하십시오.

참고 항목

작업

연습: Silverlight 비즈니스 응용 프로그램에서 데이터 표시
연습: Silverlight 비즈니스 응용 프로그램에서 인증 서비스 사용