처음이니 간단하게 프로젝트만 만들고 자야쥐..냐하하..;; 하지만!! 비록 처음이기는 하지만 매우 중요한 부분이 나오니 찬찬히 보아야 한다는..

VS2010 실행

File -> New Project

폴더 정하고, 이름 정하고 OK

요기 중요한 부분! 꼭 Enable WCF RIA Services 체크~, 그리고 OK.
처음 나오는 깨끗한 네모상자~ 음.. 아직 이 상자에 볼일은 없으니..일단 SL5_BOARD.Web -> SL5_BOARDTestPage.aspx 더블 클릭해서 열고(묻지 말고 그냥 열어주삼 할일이 있응께)

NuGet Packages를 선택..

* NuGet Packages란
NuGet is a free, open source developer focused package management system for the .NET platform intent on simplifying the process of incorporating third party libraries into a .NET application during development
이런 설명이..공짜 오픈 소스이구 닷넷 개발자를 위한..머 대략 그런 내용이니 읽고 싶다면..
http://nuget.codeplex.com/
위의 주소를 클릭.. 참 그리고 엠에스사가 요즘 여기를 통해서 이것저것 테스트 하고 있다는..가져다가 쓰기도 잘쓰고..엠에스랑 무슨 관계인지는 알 수 없음;;

* WCF RIA Services Support for EF 4.1 (and EF Code-First)
WCF 서비스 중에서 최고로 편하고, 사용하기 좋은 WCF RIA 서비스가 그동안 SP2까지 나왔지만, 여전히 EF4.1을 지원하지 앙아서 WCF RIA Service가 나오기를 손꼽아서 기다리던 중 얼마전 한 포스트에 올라온 글을 보고 NuGet Package형태로 배포가 되고 있다는 사실을 알았다. (http://varunpuranik.wordpress.com/2011/06/29/wcf-ria-services-support-for-ef-4-1-and-ef-code-first/)
중요한 2가지가 업데이트가 되었다는데,
1) DbContext base API 제공
2) Code-First support가 핵심이다.
더 자세한 정보는 ADO.NET team blog 요기서 알아보라구 하는..그래서, 이제 DbContextDbDomainService를 사용할 수 있게 되었고, Tool을 통해서 DbDomainService용 코드 생성을 지원한다고 한다.(코드 퍼스트에서는 툴을 이용할 일이 없을 듯하지만..)

**DB만드는 방법 3가지
1)) Database First : 테이블만들고, 엔티티 모델만들고, 클래스 생성해서 사용
2)) Model First : 엔티티 모델 만들고, 테이블만들고, 클래스 생성해서 사용
3)) Code First : 클래스 만들고 실행하면 테이블 만들어짐 클래스만 가지고 놀면 됨
-> 3가지 방식 중 자신에게 맞는 방식을 선택해서 만들면 된다고하는.. 어떤 방식으로 하던간에 EF4.1의 기능을 잘 사용할 수 있다.
그래서 새로나온 WCF RIA Service를 이용하기 위해서는 WCF RIA Services V1.0 RTM 버전과, SP1 or SP2 가 인스톨되어 있어야지만 한단다.(이전 강좌나 구글에서 찾으면 나온다)
그리고 마지막으로 Microsoft.ServiceModel.DomainServices.EntityFramework.dll 이 필요한데 이넘을 NuGet Package에서 다운 받아서 설치를 할 수 있는 것이다. (NuGet Package는 프로젝트 단위로 설치되기 때문에 새 프로젝트를 만들면 또 설치해줘야한다.)
http://nuget.org/List/Packages/RIAServices.EntityFramework
위의 링크가 설치할 수 있는 곳이라구 하는데 가보면

PM> Install-Package RIAServices.entityFramework라구 써있구 다운로드 링크가 업다;; 그래서, 저 문장을 처서 설치할 수 도 있고 좀 편하게 그냥 NuGet Package검색에서 찾아서 설치할수도 있다.
그게 좀전에 이야기했던 Manage NuGet Packages 메뉴라는..

위의 화면 처럼 찾아서 Install버튼을 클릭한다.(만으니까 wcf ria라고 검색해서 찾아야한다)
설치가 완료되면 녹색 체크 마크가 표시된다. 그럼 이제 Close버튼을 눌러 닫는다. 그럼 뭐가 변했는지 찾아보자

위에 사진에 가운데를 보면 EntityFramework버전이 4.1.10331.0으로 표시되는 것을 볼 수있다. 여기까지하고 실행해보면 머 빈 화면이 댕그러니 뜨기는 하지만..뭔가 뿌듯하다..음음..(나만 그런가;; 시작이 반이라니까..;;)

다음에는 클래스를 만들어서 테이블을 만들도록 하겠다.(모델 퍼스트로 그냥. 해야겠당..냐하하..코드 퍼스트는 귀차니즘이..쿨럭)


 

 

 

 

 

블로그 이미지

kaki104

This blog covers the latest technologies in Microsoft .Net. In 2020, I will be talking about Uno Platform frequently. http://youtube.com/FutureOfDotNet https://twitter.com/kaki104

댓글을 달아 주세요

1. 바로 어제 드디어 기다리고 기다리던 WCF RIA Services Support for EF 4.1 (and EF Code-First)이 나온것을 알게 되었습니다.

http://varunpuranik.wordpress.com/2011/06/29/wcf-ria-services-support-for-ef-4-1-and-ef-code-first/

아직 정식 배포 버전은 아니고 NuGet Package 형태로 제공되고 있지만, 테스트를 해본 봐로는 서버 단에서는 스트림라인드 데이터 베이스, Code-First로 작업을 하고, 클라이언트에서는 WCF RIA 4버전과 사용방법은 동일 한것으로 보였습니다.

좀더 자세한건 일단 만들어 보면 알 수 있겠죠.

그래서 이번 기회에 WCF RIA를 이용한 스트림라인드로만 구성되는 실버라이트 게시판을 만들어서 공개를 할까 합니다.

사용한 기술은 아래와 같습니다.

2. 공개 게시판

MS SQL Server Compact 4.0 : 데이터베이스

Silverlight 5 beta - MVVM 적용 : 클라이언트 기술

WCF RIA Services Support for EF 4.1 (and EF Code-First) : 네트워크 기술

MEF : 컨테이너 기술?

LINQ : 데이터 조작

컨트롤 : RadControls for Silverlight Q1 2011 사용

DataGrid로 만드는 것은 해보지 앙아서..ㅜㅜ

Prism4 : 될수 있으면 적용을 하고 싶기는 한데..어떻게 될지는 모르겠네요 저도 공부를 해야하는 분야라 - 적용을 한다면 MEF Container를 사용 할려고 합니다.

3. 프로젝트라고 거창해 보이기는 한데..그냥 지난 강좌처럼 쪼금씩 몇 회에 걸쳐서 지속적으로 하나하나 적어 볼려고 합니다. 중간 중간 소스도 올려소 직접 실행 해 보실 수 있도록 할것이며, 여기에서 만든 게시판을 가지고 진짜 사이트에 배포하는 것 까지 계획을 잡고 있습니다. 계획이 조금 거창해 보이기는 하지만..머 시간만 허락한다면...흐흐;;

4. 기본적인 테이블 구조는 제가 전에 만들었던 게시판 테이블 구조를 사용하면 되는데.. 목표는 제로보드 처럼 범용 적으로 사용 할 수 있는 게시판이 목표인데..어떤 기능이 필요한지.. 잘 모르겠네요.. 혹시 조언이 있으면 좀 부탁드립니다.

5. 구인 : 블랜드 디자인 해주실분 구합니다(무료봉사 강요예정... 나중에 저녁 정도는..). 음음..그래도 명세기 실버라이트 게시판인데 애니메이션 하나 들어가지 앙는 재미없는 게시판을 만들고 싶지는 앙네요..

6. 생각 중인 게시판 기능

6-1. 게시판 목록 조회/글쓰기/수정/삭제/리플

6-2. 로그인/로그아웃/회원가입

6-3. 관리자페이지/메뉴추가삭제/회원관리(회원목록조회/찾기/탈퇴)

헉 일단 이정도만해두 페이지 수가 좀 되는 군요.. 디자이너분이 구해지면 스토리 보드를 한번 그려봐야겠네요..일단은 테이블 정리하고 Code-First로 작업 할 것이니 클래스를 만들어야겠네요

생각처럼 멋진 게시판이 만들어 지면 좋겠내요..

그럼


 

블로그 이미지

kaki104

This blog covers the latest technologies in Microsoft .Net. In 2020, I will be talking about Uno Platform frequently. http://youtube.com/FutureOfDotNet https://twitter.com/kaki104

댓글을 달아 주세요

www.devpia.com에 올렸던 강좌입니다. 링크만 걸어 놓습니다.

Twitter Client 1

Twitter Client 2 (MVVM)

Twitter Client 3 (MEF)

Twitter Client 4 (RadGridView for RadControl)

Twitter Client 5 (Localization)

Twitter Client 6 (HierarchyChild)

Twitter Client 7 (PopupMenu)

Twitter Client 8 (Popup Window)

Twitter Client 9 (Popup Window 2)

Twitter Client 10 (MEF 2)


Daum RSS Reader

'Silverlight > ETC' 카테고리의 다른 글

Prism 4.0 Tips  (0) 2012.06.13
Telerik Report Tips  (2) 2012.06.08
Rx, Linq Tips  (0) 2012.05.04
Silverlight Standard Tips  (0) 2012.04.27
Twitter Client Lecture(강좌 목록) by Silverlight 5  (0) 2012.01.05
[Arg_COMException] error solution: perhaps  (4) 2012.01.04
블로그 이미지

kaki104

This blog covers the latest technologies in Microsoft .Net. In 2020, I will be talking about Uno Platform frequently. http://youtube.com/FutureOfDotNet https://twitter.com/kaki104

댓글을 달아 주세요

간단한 콤보박스에 바인딩하는 예제를 만들어 보았다. 일단 화면을 보자

WCF RIA 서비스를 이용해서 3개의 데이터를 조회한 후에 상품은 데이터 그리드에 바인딩하고, 오른쪽 각각의 콤보박스에 카테고리, 공급자를 바인딩을 해 놓았다. 그리고 그리드에서 선택된 데이터를 변경하면 콤보박스에 데이터가 변경되고, 콤보박스에서 데이터를 변경하면 그리드의 데이터가 변경되도록 만들어 놓았다.

바인딩의 기초적인 내용인데 처음에 만들려고 하면 좀 까다로운 부분이 있다. 예제를 참고해서 연습하면 바인딩 마스터를 할 수 있을 것이다.

ComboBoxSampleView.xaml

<UserControl x:Class="SL4_RIA_Sample.ComboBoxSampleView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400"
    xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices"
    xmlns:my="clr-namespace:SL4_RIA_Sample.Web"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
   
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="0.5*" />
        </Grid.ColumnDefinitions>


        <!--상품 조회용 리아 컨트롤-->

        <riaControls:DomainDataSource AutoLoad="True" Height="0" LoadedData="productDomainDataSource_LoadedData" x:Name="productDomainDataSource" QueryName="GetProductsQuery" Width="0">
            <riaControls:DomainDataSource.DomainContext>
                <my:DomainService1 />
            </riaControls:DomainDataSource.DomainContext>
        </riaControls:DomainDataSource>


        <!--카테고리 조회용 리아컨트롤-->

        <riaControls:DomainDataSource AutoLoad="True" Height="0" LoadedData="categoryDomainDataSource_LoadedData" x:Name="categoryDomainDataSource" QueryName="GetCategoriesQuery" Width="0">
            <riaControls:DomainDataSource.DomainContext>
                <my:DomainService1 />
            </riaControls:DomainDataSource.DomainContext>
        </riaControls:DomainDataSource>


         <!--공급자 조회용 리아컨트롤-->

        <riaControls:DomainDataSource AutoLoad="True" Height="0" LoadedData="supplierDomainDataSource_LoadedData" x:Name="supplierDomainDataSource" QueryName="GetSuppliersQuery" Width="0">
            <riaControls:DomainDataSource.DomainContext>
                <my:DomainService1 />
            </riaControls:DomainDataSource.DomainContext>
        </riaControls:DomainDataSource>


        <!--그리드-->

        <sdk:DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Data, ElementName=productDomainDataSource}" x:Name="productDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn x:Name="product_NameColumn" Binding="{Binding Product_Name}" Header="Product Name" Width="SizeToHeader" />
             <sdk:DataGridTextColumn x:Name="english_NameColumn" Binding="{Binding English_Name, Mode=TwoWay}" Header="English Name" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="category_IDColumn" Binding="{Binding Category_ID, Mode=TwoWay}" Header="Category ID" Width="SizeToHeader" />
             <sdk:DataGridTextColumn x:Name="product_IDColumn" Binding="{Binding Product_ID, Mode=OneWay}" Header="Product ID" IsReadOnly="True" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="supplier_IDColumn" Binding="{Binding Supplier_ID, Mode=TwoWay}" Header="Supplier ID" Width="SizeToHeader" />
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>

 

        <StackPanel Grid.Column="1" Margin="4,0,0,0" >
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Product Name" Width="90"/>
                <TextBox Text="{Binding SelectedItem.Product_Name, ElementName=productDataGrid, Mode=TwoWay}" />
            </StackPanel>


            <!--카테고리 콤보박스-->

            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Category" Width="90" />
                <ComboBox ItemsSource="{Binding Data, ElementName=categoryDomainDataSource, Mode=OneWay}" DisplayMemberPath="Category_Name" SelectedValuePath="Category_ID" SelectedValue="{Binding SelectedItem.Category_ID, ElementName=productDataGrid, Mode=TwoWay}" />
            </StackPanel>


            <!--공급자 콤보박스-->
            <StackPanel Orientation="Horizontal">
             <TextBlock Text="Supplier" Width="90" />
             <ComboBox ItemsSource="{Binding Data, ElementName=supplierDomainDataSource, Mode=OneWay}" DisplayMemberPath="Company_Name" SelectedValuePath="Supplier_ID" SelectedValue="{Binding SelectedItem.Supplier_ID, ElementName=productDataGrid, Mode=TwoWay}" />
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>


소스를 실행하여 분석해보면...
 어떻게 바인딩을 했는지 확인 할 수 있다. 궁금한 점이나 요청사항은 항상 리플로 남겨주면 매우 친절한 설명을 추가하도록 하겠다..^^

블로그 이미지

kaki104

This blog covers the latest technologies in Microsoft .Net. In 2020, I will be talking about Uno Platform frequently. http://youtube.com/FutureOfDotNet https://twitter.com/kaki104

댓글을 달아 주세요

지난번 강좌에 사진 촬영에 대한 내용을 다루었다..그러나 사진 촬영만 하면 무었을 하겠는가..어디다가 저장을 해야하는데..물론 실버라이트는 기본적으로 격리저장소(Isolated Storage)를 제공하고 있어서, 처음에는 사진을 촬영해서 그곳에 저장하고 그걸 다시 서버로 전송을 할려는 계획을 세우고 이것 저것 찾아보았는데..

서버로 파일을 업로드할려고 찾았던 컨트롤이 절대 경로를 가지고 파일 정보를 가지고 올 수 있어야지만, 업로드가 가능했던 것이다.하지만, 격리저장소는 OOB 상태가 아니라면 실버라이트4 응용프로그램이 절대 경로를 사용해서는 접근이 불가능하다..(이런 내용을 알기위해 삽질했던 시간이 2틀 정도였던 것 같다..ㅡㅡ;;;)

그렇다면, 사진을 찍어서 로컬에 저장하지 않고, 그냥 서버로 바로 던져서 서버에 저장을 해야겠다는 결론을 내리고 사이트를 검색하다가 찾은 것이 WCF RIA Service를 사용한 파일 업로드 방식이였다. 처음에 그걸 발견하고, 완전 기뻐서 땡큐를 연발하면서 리플을 남겼었다.

강좌를 위해서 소스를 좀 수정하고, 간단하게 목록까지 볼 수 있도록 수정을 했다.

이 화면의 구성은 왼쪽 리스트 박스에서 클릭을 하면 오른쪽에 큰 이미지를 보여 줄려는 의도로 만들었다. 그러나..시간 관계상..해당 기능을 구현하지는 않았다. 여러분들께서 만들어서 올려 줄것이라고 믿는다. ^^ 또..사진 촬영을 2번하면 화면이 먹통이 되는 이상 현상이 있는데..이 부분도 수정해서 완성 올려주면 좋겠다. 그래서 구현되어 있는 기능은

1) 웹켐 촬영

2) 촬영된 이미지를 Jpeg로 변환

3) 변환된 이미지를 WCF RIA Service를 이용해서 서버로 전송

4) 서버에 이미지 저장

5) 저장된 이미지 목록 WCF RIA Service로 조회

6) 조회된 파일 목록을 가지고 리스트박스에 뿌려주면서 실제 이미지를 웹서버에서 불러와서 보여준다.


1. 서버작업

SL4_RIA_Sample.Web 프로젝트에

Assets 폴더를 하나 추가
FileHandler.cs, WebFile.cs를 추가한다.

WebFile.cs

using System.ComponentModel.DataAnnotations;

namespace SL4_RIA_Sample.Web.Assets
{
    //전송될 파일 클래스
    public class WebFile
    {  //WCF RIA Service의 DTO로 사용하기 위해서는 반드시 Key가 필요하다.
        [Key]
        public string FileName { get; set; }
        public byte[] FileContent { get; set; }
    }
}

무지 심플한 클래스다. 이 클래스가 파일을 마치 레코드 다루듯이 가지고 올것이다.

FileHandler.cs

using System.Web;
using System.Web.Configuration;
using System.IO;

namespace SL4_RIA_Sample.Web.Assets
{
    /// <summary>
    /// http://community.infragistics.com/blogs/anton_staykov/archive/2010/04/28/implementing-simple-file-upload-using-silverlight-4-drag-amp-drop-feature-and-infragistics-compression-library.aspx
    /// 이곳에 있던 소스를 참고로 수정
    /// 파일핸들러 스택틱 클래스 웹파일을 로컬(서버)에 저장하는 역할을 한다.
    /// </summary>
    public static class FileHandler
    {
        /// <summary>
        /// 파일전송 함수
        /// </summary>
        /// <param name="file">웹파일 클래스</param>
        public static void HandleFile(WebFile file)
        {
            //업로드 폴더 지정(Web.Config 파일에 절대 경로 존재)
            string uploadDir = WebConfigurationManager.AppSettings["UploadDir"];
            //업로드 폴더가 존재하면
            if (!string.IsNullOrEmpty(uploadDir))
            {
                //업로드 폴더명에 ~/ 이런 글씨가 있으면
                if (uploadDir.IndexOf("~/") == 0)
                    //상대경로를 절대경로로 변경
                    uploadDir = HttpContext.Current.Server.MapPath(uploadDir);
                //업로드 폴더명에 /이것만 있으면
                if (uploadDir.LastIndexOf("/") == uploadDir.Length - 1)
                    //절대경로이니 대충 짤라서 사용
                    uploadDir = uploadDir.Substring(0, uploadDir.Length - 1);

                //저장할 풀경로를 만들고
                string fullFileName = string.Format("{0}/{1}", uploadDir, file.FileName);

                //파일 존재여부 확인
                if (File.Exists(fullFileName))
                {
                    //확장자
                    string ext = fullFileName.Substring(fullFileName.LastIndexOf("."));
                    //파일명
                    string fName = fullFileName.Substring(0, fullFileName.LastIndexOf("."));
                    //풀파일명
                    fullFileName = string.Format("{0}_1{1}", fName, ext);
                }
                //저장~
                File.WriteAllBytes(fullFileName, file.FileContent);
            }
        }
    }
}

위의 소스를 보니 Web.config에 업로드 폴더도 지정해야한다.

Web.config 파일에 추가
  <!--업로드폴더 지정-->
  <appSettings>
    <add key="UploadDir" value="~/UserUploads" />
  </appSettings>

음..그럼 이걸 사용하는 WCF RIA Service를 만들자

FileUploaderDomainService.cs

namespace SL4_RIA_Sample.Web
{
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using System.Web;
    using System.Web.Configuration;
    using IDApp.Web.Assets;

    /// <summary>
    /// 파일 업로드용 WCF RIA Service 생성
    /// </summary>
    [EnableClientAccess()]
    public class FileUploaderDomainService : DomainService
    {
        //파일 목록들 조회
        public IQueryable<WebFile> GetFiles()
        {
            //업로드 폴더명 가지고 가서
            string path = WebConfigurationManager.AppSettings["UploadDir"];

            //웹파일 정보 리스트 객체를 만들고,
            List<WebFile> webFiles = new List<WebFile>();

            //폴더에 내용이 없으면 그냥 빈거 던지고
            if (string.IsNullOrEmpty(path))
                return webFiles.AsQueryable();

            //디렉토리 정보를 가지고 오고
            DirectoryInfo di = new DirectoryInfo(HttpContext.Current.Server.MapPath(path));
            //파일정보도 가지고 오고
            foreach (FileInfo file in di.GetFiles())
            {
                //웹파일 정보 리스트에 하나씩 추가하고
                webFiles.Add(new WebFile { FileName = file.Name });
            }
            //결과를 던진다.
            return webFiles.AsQueryable();
        }

        //파일 업로드 함수
        public void InsertFile(WebFile file)
        {
            FileHandler.HandleFile(file);
        }
    }
}

마지막으로 프로젝트에 UserUploads 폴더를 추가해 놓는다.
여기 까지 작업을 하면 서버쪽 작업은 일단 완료된다. 컴파일을 해서 오류가 있는지 확인해 본다. 오류가 없으면 클라이언트쪽 작업을 시작한다.


2. 클라이언트 작업

일단 사진을 촬영하면 BitmapImage으로 만들어 진다. 우린 이걸 Jpeg로 변환해야하는데 이미지 컨버트용 오픈소스 라이브러리를 사용한다.

FluxJpeg 라는 라이브러리(https://github.com/briandonahue/FluxJpeg.Core)
위의 주소를 가면 전체 소스를 Download를 받을 수 있고, 다운로드를 받아서 소스를 VS2010으로 열고, 빌드를 해주면 FJ.Core.dll이란 파일이 만들어 진다. 그 DLL파일을 프로젝트에 추가해서 사용한다. 일단 이 소스에도 해당 Dll파일이 포함되어져 있다. Bin\Debug 폴더를 보면 FJ.Core.dll파일을 찾을 수 있다. 파일을 폴더에 복사해 놓은 후 Add Reference로 해당 dll을 프로젝트 리퍼런스로 추가해 놓는다. 지금 추가한 라이브러리를 편하게 사용하기 위해서 확장메소드 기능을 사용한다.


Extension.cs
이 확장메소드의 소스는 복사해 온것이기 때문에..주석이 없다..

using System.IO;
using System.Windows.Media.Imaging;
using FluxJpeg.Core;
using FluxJpeg.Core.Encoder;

namespace SL4_RIA_Sample
{
    //확장메소드 만들기
    public static class Extension
    {
        public static void EncodeJpeg(this WriteableBitmap bitmap, MemoryStream stream, int quality = 90)
        {
            int width = bitmap.PixelWidth;
            int height = bitmap.PixelHeight;
            int bands = 3;
            byte[][,] raster = new byte[bands][,];
            for (int i = 0; i < bands; i++)
            {
                raster[i] = new byte[width, height];
            }
            for (int row = 0; row < height; row++)
            {
                for (int column = 0; column < width; column++)
                {
                    int pixel = bitmap.Pixels[width * row + column];
                    raster[0][column, row] = (byte)(pixel >> 16); //R
                    raster[1][column, row] = (byte)(pixel >> 8);  //G
                    raster[2][column, row] = (byte)pixel;         //B
                }
            }
            ColorModel model = new ColorModel { colorspace = ColorSpace.RGB };
            FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);

            JpegEncoder encoder = new JpegEncoder(img, quality, stream);
            encoder.Encode();

            stream.Seek(0, SeekOrigin.Begin);
        }
    }
}

확장메소드가 무엇인지..어떻게 사용하는지는 잠시 후에 보도록 하겠다.

확장메소드까지 작업을 했다면..사진을 보여주는 화면을 보도록 하자..

PhotoView.xaml

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:SL4_RIA_Sample_Web_DomainService="clr-namespace:SL4_RIA_Sample.Web"
    xmlns:local="clr-namespace:SL4_RIA_Sample" x:Class="SL4_RIA_Sample.PhotoView"
    mc:Ignorable="d" Loaded="UserControl_Loaded"
    d:DesignHeight="300" d:DesignWidth="400">

    <UserControl.Resources>
        <local:ImageFullPathConverter x:Key="ImageFullPathConverter"/>

        <!--리스트박스에서 사용하는 데이터 템플릿-->
        <DataTemplate x:Key="ListDataTemplate">
            <Grid d:DesignWidth="97" d:DesignHeight="99">
                <Grid.RowDefinitions>
                    <RowDefinition Height="0.192*"/>
                    <RowDefinition Height="0.808*"/>
                </Grid.RowDefinitions>
                <TextBlock TextWrapping="Wrap" Text="{Binding FileName}"/>
                <Viewbox Grid.Row="1" HorizontalAlignment="Left">
                    <Image Source="{Binding FileName, Converter={StaticResource ImageFullPathConverter}}"
                           Width="120" Margin="5"/>
                </Viewbox>
            </Grid>
        </DataTemplate>
    </UserControl.Resources>
   
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="177" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="38" />
            <RowDefinition Height="261*" />
        </Grid.RowDefinitions>
       
        <Grid.DataContext>

            <!--블랜드에서 바인딩 작업 할려고 추가해 놓았던 것-->
            <SL4_RIA_Sample_Web_DomainService:FileUploaderDomainContext/>
        </Grid.DataContext>

        <!--상단 버튼-->       
        <StackPanel Orientation="Horizontal" Grid.ColumnSpan="2">
            <Button Content="웹켐 촬영" Width="80" Margin="4" Click="Button_Click" />
            <Button Content="이미지 목록" Width="80" Margin="4" Click="Button_Click_1" />
        </StackPanel>

        <!--리스트박스-->
        <ListBox Grid.Row="1"
                 ItemTemplate="{StaticResource ListDataTemplate}"
                 ItemsSource="{Binding WebFiles, Mode=OneWay}"
                 HorizontalContentAlignment="Stretch"
                 VerticalContentAlignment="Stretch"/>
       
    </Grid>
</UserControl>


PhotoView.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 SL4_RIA_Sample.Web;

 

namespace SL4_RIA_Sample
{
    public partial class PhotoView : UserControl
    {
        //WCF RIA Service 컨텍스트 생성
        FileUploaderDomainContext ctx;

 

        public PhotoView()
        {
            InitializeComponent();
        }

 

        /// <summary>
        /// 촬영시작 버튼
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            WebCam_Child webCam = new WebCam_Child();
            webCam.Show();
        }

        /// <summary>
        /// 유저컨트롤 로드 완료 이벤트
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {

            //초기화
            ctx = new FileUploaderDomainContext();

            //DataContext에 도메인서비스 자체를 넣어놓음 (물론 좋은 방법은 아니니..옵저블 컬렉션을 사용 권고)

            LayoutRoot.DataContext = ctx;
        }

 

        /// <summary>
        /// 이미지 목록 버튼
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            ctx.Load(ctx.GetFilesQuery(), true);
        }
    }
}

여기까지 작업을 했으면 중요한 한가지가 있다. 리스트박스에 이미지 이름을 바인딩하는데 이미지 이름 바인딩 하면서 바로 ImageFullPathConverter가 필요한데..여기서 하는 일이 중요하다.


ImageFullPathConverter.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 System.Windows.Data;

 

namespace SL4_RIA_Sample
{
    public class ImageFullPathConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string fileName = value as string;
            string ReturnValue;

            //호스트 Uri구함
            string hostUri = App.Current.Host.Source.ToString().Replace(App.Current.Host.Source.LocalPath, "");
            ReturnValue = hostUri + "/UserUploads/" + fileName;

            return ReturnValue;
        }


        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

이미지들은 서버에 존재하기 때문에 서버의 주소를 이미지 이름 앞에 추가해 주는 기능을 한다.

그럼 이제 마지막으로


WebCam_Child.xaml.cs 파일을 수정해 보자


using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
using SL4_RIA_Sample.Web;
using SL4_RIA_Sample.Web.Assets;
using System.ServiceModel.DomainServices.Client;

namespace SL4_RIA_Sample
{
    public partial class WebCam_Child : ChildWindow
    {
        private CaptureSource _capture;
        //일단 여기다가 저장해놨다가, 성공하면 프로퍼티로 이동
        private string captureFileName;
        //다른 화면에서 저장된 파일명 참고
        public string CaptureFileName;


        public WebCam_Child()
        {
            InitializeComponent();
        }

        private void ChildWindow_Loaded(object sender, RoutedEventArgs e)
        {
            //캡춰소스 인스턴스
            _capture = new CaptureSource();
            _capture.CaptureImageCompleted += new EventHandler<CaptureImageCompletedEventArgs>(_capture_CaptureImageCompleted);
        }

        /// <summary>
        /// 이미지 캡처 완료되었을 때 발생하는 이벤트
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _capture_CaptureImageCompleted(object sender, CaptureImageCompletedEventArgs e)
        {
            //이미지 캡춰가 완료되면 여기로
            WriteableBitmap wb = e.Result;
            //화면에 촬영된 이미지 보여주기
            if (_capture != null)
            {
                _capture.Stop();
                ImageBrush image = new ImageBrush();
                image.ImageSource = wb;
                rectVideo.Fill = image;
            }

            //파일명 생성
            string name = Guid.NewGuid().ToString() + ".bmp";
            //메모리 스트림 인스턴스
            MemoryStream stream = new MemoryStream();

            //확장메소드를 이용해서 이미지를 jpeg 포멧으로 변환
            wb.EncodeJpeg(stream);

            //WCF RIA Service 컨텍스트 생성
            FileUploaderDomainContext ctx = new FileUploaderDomainContext();
            //웹파일 정보 하나 만들고
            WebFile file = new WebFile { FileName = name };
            //파일 컨텐츠에 메모리 스트림의 버퍼데이터를 쓸어 넣는다.
            //메모리 스트림아니라 파일 스트림의 데이터도 넣을 수 있다.
            file.FileContent = stream.GetBuffer();
            //웹파일스에..방금 만든거 추가..마치 레코드 추가하듯이
            ctx.WebFiles.Add(file);
            //그리고 세이브체인지 호출~
            ctx.SubmitChanges(SubmitCallBack, null);
            //전송한 파일 이름을 저장해 놓고
            captureFileName = name;
        }

        /// <summary>
        /// 세이브체인지 완료 콜백함수
        /// </summary>
        /// <param name="op"></param>
        private void SubmitCallBack(SubmitOperation op)
        {
            //에러가 있으면 에러 보여주고 끝~
            if (op.HasError)
            {
                MessageBox.Show(op.Error.Message);
                this.DialogResult = false;
                CaptureFileName = "";
            }
            else
            { //여긴 저장 완료~
                MessageBox.Show("작업을 완료했습니다.");
                this.DialogResult = true;
                CaptureFileName = captureFileName;
            }
            //팝업 화면 닫기
            this.Close();
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            //캡춰 시작
            _capture.CaptureImageAsync();
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }

        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            Button btn = ((Button)sender);

            if (_capture != null)
            {
                //일단 동작 정지
                _capture.Stop();

                if (btn.Content.ToString() == "촬영시작")
                {
                    //기본 비디오 디바이스를 가지고옴
                    _capture.VideoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
                    //기본 오디오 디바이스를 가지고옴
                    _capture.AudioCaptureDevice = CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice();

                    //비디오 브러쉬 만들고
                    VideoBrush videoBrush = new VideoBrush();
                    videoBrush.Stretch = Stretch.Uniform;
                    videoBrush.SetSource(_capture);
                    rectVideo.Fill = videoBrush;
                    // request user permission and display the capture
                    if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
                    {
                        _capture.Start();
                        btn.Content = "촬영종료";
                    }
                }
                else
                {
                    btn.Content = "촬영시작";
                }
            }
        }
    }
}

 

3. 간단하게 만들려고 했는데..
일이 커져버렸다..;; 배보다 배꼽이 더 커진..흐흐..서버로 파일을 업로드 하는 방법도 이렇게 사용해서 올릴 수 있다. 어떤 파일이라도 스트림형태로 읽어 들인다면, 그 스트림의 버퍼를 WebFile 클래스에 쑤셔 넣어서 SubmitChange()만 호출 한다면 자동으로 올라간다..앞으로 실버라이트에서 WCF RIA Service를 사용한 완성된 파일 업로드 기능을 기대하며 이번 강좌를 마친다.

블로그 이미지

kaki104

This blog covers the latest technologies in Microsoft .Net. In 2020, I will be talking about Uno Platform frequently. http://youtube.com/FutureOfDotNet https://twitter.com/kaki104

댓글을 달아 주세요