2017년 2월 20일 월요일

[재직자환급교육구로IT학원/IT실무교육/닷넷학원/C#교육/자마린/WPF학원추천_탑크리에듀]닷넷, C# WPF소개, 개요_WPF출현배경 및 간단한 예제_WPF학원/WPF교육/W

닷넷, C# WPF소개, 개요_WPF출현배경 및 간단한 예제_WPF학원/WPF교육/WPF강좌

1.1 WPF 소개?

2002년 정식으로 출시된 닷넷 프레임워크에서 윈폼 이라는 기술이 등장하여 윈도우 응용프로그램 개발을 주도했지만 요구가 다양해지면서 비디오, 미디어, 애니메이션, 2D 3D그래픽 등을 다이나믹하게 사용할 수 있기를 원했다.
이러한 부분이 기존의 윈도우 플랫폼들에서 독립된 기술들로 분산되어 있었고 여러 다른 기술들을 각각 모두 이해해야만 통합된 개발이 가능했다. 결국 통합된 기술이 필요했는데 그러한 요구에서 만든 기술이 바로 WPF(Windows Presentation Foundation) 이다.
WPF는 닷넷3.X부터 추가된 기술로  Vista에서 UX를 구현하기 위해 탄생되었으며 비주얼 스튜디오 2008에 추가 되었다.
시각적으로 뛰어난 사용자 환경에서 윈도우 클라이언트 응용 프로그램을 만들 수 있는 차세대 프레젠테이션 시스템으로 WPF를 이용하면 광범위한 독립 실행형 응용 프로그램과 브라우저에서 호스팅되는 응용 프로그램을 모두 만들 수 있다.
WPF를 사용하여 Extensible Application Markup Language (XAML), 컨트롤, 데이터 바인딩, 레이아웃, 2-D 및 3-D 그래픽, 애니메이션, 스타일, 템플릿, 문서, 미디어, 텍스트, 입력 체계 등의 광범위한 응용 프로그램 개발이 가능하다.
클래스를 인스턴스화한 후 속성을 설정하고, 메서드를 호출하고, 이벤트를 처리하는 등의 모든 작업을 C#, Visual Basic 등의 익숙한 .NET Framework 프로그래밍 언어로 수행할 수 있다.
WPF는 대부분 System.Windows 네임스페이스에 있는 클래스, 인터페이스들을 다룬다.
일반적으로 XAML 태그는 UI를 구현하는 데 사용되고 비하인드코드로 프로그램의 동작을 구현한다.
XAML은 선언적으로 UI를 구현하는 데 사용되는 XML 기반 태그 언어로 일반적으로 창, 대화 상자, 페이지 및 사용자 정의 컨트롤을 만들고 이러한 항목을 컨트롤, 도형 및 그래픽으로 채우는 데 사용된다.

아래는 XAML을 사용하여 Button이 있는 Window를 구현한 예문이다.

<Window
    Title="Window with Button"
    Width="250" Height="100">

  <!-- 윈도우에 버튼추가 -->
  <Button Name="button" Click="button_Click">Click Me!</Button>

</Window>

아래는 위에서 정의한 버튼의 Click 이벤트를 구현한 C#코드이다.

using System.Windows; // Window, RoutedEventArgs, MessageBox

namespace SDKSample
{
    public partial class AWindow : Window
    {
        public AWindow()
        {
            // InitializeComponent call is required to merge the UI
InitializeComponent();
        }

        void button_Click(object sender, RoutedEventArgs e)
        {
            // 메시지 박스를 띄움
            MessageBox.Show("Hello, Windows Presentation Foundation!");
        }
    }
}



fe582bd7f4b67a8fa7c9e02e5a2702c0_1481944

[재직자환급교육구로IT학원/IT실무교육/닷넷학원/C#교육/자마린/WPF학원추천_탑크리에듀][자마린 에뮬레이터]Android_Accelerated_x86 실행시 배포오류_Hyper-V be

[자마린 에뮬레이터]Android_Accelerated_x86 실행시 배포오류_Hyper-V before using the Android Emulator

아래 내용 참조하세요.

CPU acceleration status: Please disable Hyper-V before using the Android Emulator

C:\WINDOWS\system32>bcdedit /set hypervisorlaunchtype off

그리고 PC 리부팅 하시면 됩니다.

[재직자환급교육구로IT학원/IT실무교육/닷넷학원/C#교육/자마린/WPF학원추천_탑크리에듀]C# 프로젝트에 DLL(C++) 추가 방법 : Create The IDL File

[ Create The IDL File] 

1. “Microsoft Visual Studio .NET 2003” 실행 

2.  “도구” -> "OLE/COM  Object Viewer” 실행 

3.  “File” -> “View TypeLib…” 선택 

4. 해당 COM.DLL or COM.EXE를 Open 한다. 

5. ROOT 선택시 우측 화면에 idl 파일 정보를 확인 할 수 있다. 

6. “File” -> “Save As…” 선택 

7. 저장하려는 폴더 선택 및 idl 파일의 이름 입력하고 저장한다. 

8. idl파일 생성 완료. 

============================================================ 
그림과 같이 첨부한 강좌인데 그림 첨부 되지 않네요 정확한 자료는 

주소 : http://comalchemy.tistory.com/entry/Create-The-IDL-File 

확인하시면 됩니다. 
============================================================

[재직자환급교육구로IT학원/IT실무교육/닷넷학원/C#교육/자마린/WPF학원추천_탑크리에듀][윈도우7, 64비트, ORAOLEDB 사용하기,오라클11g]소스,예제

[윈도우7, 64비트, ORAOLEDB 사용하기,오라클11g]소스,예제

64비트에서는 32비트에서 사용했던 MSDAORA 라는 프로바이더는 사용할 수가 없다.

1. 오라클 클라이언트를 설치

다음 URL에서 64비트 오라클 클라이언트 11g용을 받자.

http://www.oracle.com/technetwork/database/enterprise-edition/downloads/112010-win64soft-094461.html

2. 오라클 클라이언트를 D드라이브에 설치했다면 아래처럼 오라클홈 디렉토리가 형성될 것이다.

D:\app\ooo\product\11.2.0\client_1

그아래 Network\Admin 폴더에 아래 내용으로 tnsnames.ora 파일을 만들자.

ONJ = 
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS=(PROTOCOL=TCP)(HOST = 192.168.0.27)(PORT=1521))
)
(CONNECT_DATA =
(SERVICE_NAME = onj)
)
)



3. C# 소스

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.OleDb;

namespace ConsoleApplication20
{
    class Program
    {
        static void Main(string[] args)
        {
            OleDbConnection myOleDbConnection =
                new OleDbConnection("Provider=ORAOLEDB.ORACLE;data source=onj;User ID=scott;Password=tiger");
            OleDbCommand myOleDbCommand = myOleDbConnection.CreateCommand();

            //CommendText에 직접 테이블 명을 기술하겠다는 의미
            myOleDbCommand.CommandType = CommandType.TableDirect;

            myOleDbCommand.CommandText = "EMP"; //테이블명이다. 

            myOleDbConnection.Open();

            OleDbDataReader myOleDbDataReader = myOleDbCommand.ExecuteReader();

            //전체 EMP 테이블의 데이터중 2건만 출력하자.
            for (int count = 1; count <= 2; count++)
            {
                myOleDbDataReader.Read();
                Console.WriteLine("myOleDbDataReader[\" EMPNO\"] = " + myOleDbDataReader["EMPNO"]);
                Console.WriteLine("myOleDbDataReader[\" ENAME\"] = " + myOleDbDataReader["ENAME"]);
                Console.WriteLine("myOleDbDataReader[\" SAL\"] = " + myOleDbDataReader["SAL"]);
            }
            myOleDbDataReader.Close();
            myOleDbConnection.Close();
        }
    }
}

[재직자환급교육구로IT학원/IT실무교육/닷넷학원/C#교육/자마린/WPF학원추천_탑크리에듀]닷넷,C#에서 int vs int?

닷넷,C#에서 int vs int? 

?는 Nullable의 의미이다, 즉 int? 는 Nullable<int>

아래의 예문을 보자.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(RetAge("홍길동"));
            Console.WriteLine(RetAge(null));
        }

         static int?  RetAge(string name)
        {
            if (name == null)
            {
                return null;
            }

            return 22;
        }
    }
}


[결과]
22

계속하려면 아무 키나 누르십시오 . . .

[국비지원IT교육/자마린교육/C#/닷넷학원/WPF교육/ADO.NET학원추천_탑크리에듀]C# 프로젝트에 DLL(C++) 추가 방법 : Create The TLB File

C# 프로젝트에서 필요한 Strong Named Wrapper Assembly를 생성하기 위해 
서는  TLB 파일이 필요하다. 먼저 TLB파일을 생성하기 위해 먼저 IDL 파일이 
존재 해야 한다. IDL 파일 생성은 "Create The IDL File"을 참고한다. TLB 
파일 생성 방법은 다음과 같다. 

1. “Microsoft Visual Studio.NET 2003” 실행 
  
2. 상위 메뉴에서  "파일"  -> “새로 만들기” -> “프로 젝트” 실행 

3. “Visual C++ 프로젝트” -> “Win32” -> “Win32 프로젝트” 
    -> 프로젝트 “생성” 설정 -> “확인” 선택 

4.  “응용 프로그램 설정” 선택 

5. “응용 프로그램 종류” : “DLL “ 선택, “추가 옵션” : “빈 프로젝트” 선택 
  
6.  “솔루션 탐색기” -> “프로 젝트” -> “추가” -> “기존 항목 추가” 선택 
  
7. 생성된 ild 파일 추가 

8. “Release”모드 선택 -> 프로젝트 빌드 실행 

9. Release 폴더에 tlb파일 생성 완료. 

============================================================ 
그림과 같이 첨부한 강좌인데 그림 첨부 되지 않네요 정확한 자료는 

주소 : http://comalchemy.tistory.com/entry/Create-The-TLB-File 

확인하시면 됩니다. 
============================================================ 

[국비지원IT교육/자마린교육/C#/닷넷학원/WPF교육/ADO.NET학원추천_탑크리에듀][윈도우,64비트,ASP.NET,ODP.NET오류]OraOLEDB.Oracle provider is not registered…

[윈도우,64비트,ASP.NET,ODP.NET오류]OraOLEDB.Oracle provider is not registered on the local machine, ODAC32비트, ODAC64비트, ORACLE OLEDB

환경 : 윈도우7 64비트
오라클 : 11.2....
비주얼 스튜디오 2010

수없이 많은 글을 보고 다해보았지만 잘 되지 않아 마지막 방법을 썼다.


1. ODAC 32비트를 먼저 설치하고 , ODAC 64비트를 설치하면 오라클 접속 잘된다.

ODAC는 다음 URL에서 다운로드 하자.
http://www.oracle.com/technetwork/topics/dotnet/downloads/index.html


- 설치 시 각각 홈디렉토리는 따로 주고, 홈디렉토리 및 그아래 BIN 폴더 각각 경로(PATH)에 추가.

- 각각의 홈디렉토리 아래 network\admin에 tnsnames.ora 파일을 만들자.

[예, 아래 onj라는 이름이 tns이름이며 오라클 접속시 data source 명으로 입력한다.]

onj=
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST =192.168.0.27)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = onj)
    )
  )



2. 비주얼 스튜디오 프로젝트 속성 -> 빌드 -> platform target 은 "ANY CPU"로 하고...

3. IIS에서 사이트의 응용프로그램 풀 --> 고급설정 에서  "32비트 응용프로그램 사용"을 "TRUE"로 하자.


[예제]


<%@ OutputCache Duration="10" VaryByParam="deptno" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<html>
<script language="C#" runat="server">
void Paging(Object src, System.Web.UI.WebControls.DataGridPageChangedEventArgs e) {
MyDataGrid.CurrentPageIndex = e.NewPageIndex;
Bind();
}
void Page_Load(Object Src, EventArgs E ) {
if (!Page.IsPostBack)
Bind();
}
void Bind() {
String selectCmd;
String deptno = Request["deptno"];
if( deptno == null ) {
selectCmd = "select empno, ename, sal, deptno from emp";
}
else {
selectCmd = "select empno, ename, sal, deptno from emp where deptno = " + deptno ;
}
string conStr = "Provider=OraOLEDB.Oracle;data source=ONJ;User ID=scott;Password=tiger";
OleDbConnection myConnection = new OleDbConnection(conStr);
OleDbDataAdapter adapter = new OleDbDataAdapter(selectCmd, myConnection);
DataSet ds = new DataSet();adapter.Fill(ds);
MyDataGrid.DataSource=new DataView(ds.Tables[0]);
MyDataGrid.DataBind();
TimeMsg.Text = DateTime.Now.ToString("G");
}
</script>
<body>
    <form id="form1" runat="server">
    <h3>
        <font face="Verdana">출력캐싱사용하기:</font></h3>
    <b>부서코드별보기:<%=Request["deptno"]%></b>
    <table cellspacing="0" cellpadding="3" rules="all" style="border-left-color: black;
        border-bottom-color: black; width: 700px; border-top-color: black; border-collapse: collapse;
        background-color: #aaaadd; border-right-color: black">
        <tr>
            <td>
                <a href="outputcashing.aspx?deptno=10">10번부서</a>
            </td>
            <td>
                <a href="outputcashing.aspx?deptno=20">20번부서</a>
            </td>
            <td>
                <a href="outputcashing.aspx?deptno=20">30번부서</a>
            </td>
        </tr>
    </table>
    <p>
        <asp:DataGrid ID="MyDataGrid" runat="server" Width="700px" BackColor="#CCCCFF" BorderColor="Black"
            CellPadding="3" Font-Name="Verdana" Font-Size="8pt" HeaderStyle-BackColor="#aaaadd"
            Height="153px" Font-Names="Verdana" PageSize="3" AllowPaging="True" AllowSorting="True"
            OnPageIndexChanged="Paging">
            <FooterStyle BackColor="#99CCFF" BorderStyle="Solid" HorizontalAlign="Center" />
            <HeaderStyle BackColor="#AAAADD"></HeaderStyle>
            <PagerStyle Mode="NumericPages" />
        </asp:DataGrid>
        <p>
            <i>마지막생성일시:</i><asp:Label ID="TimeMsg" runat="server" /></p>
    </form>
</body>
</html>

2017년 2월 14일 화요일

[국비지원IT교육/자마린교육/C#/닷넷학원/WPF교육/ADO.NET학원추천_탑크리에듀](WPF예제)데이터 바인딩을 이용한 계산기 실습(MVVM, ViewModel)_추

(WPF예제)데이터 바인딩을 이용한 계산기 실습(MVVM, ViewModel)_추천닷넷/C#/자마린/WPF 실무교육센터 
n  지금까지 배운 데이터 바인딩 및 MVVM을 이용하여 간단한 계산기를 구현해 보자.
n  MainWindow.xaml
<Window x:Class="CalculatorNew.MainWindow"
        xmlns:local="clr-namespace:Calc"
        Title="Topcredu.co.kr WPF Calculator" Height="350" Width="425">

    <Window.Resources>
        <local:CalcViewModel x:Key="calcViewModel"/>
    </Window.Resources>
   
    <Grid HorizontalAlignment="Center"
        VerticalAlignment="Center">

        <!-- Grid의 행과 열을 정의 -->
        <Grid.RowDefinitions>
            <RowDefinition Height="60" />
            <RowDefinition Height="60" />
            <RowDefinition Height="60" />
            <RowDefinition Height="60" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="60" />
            <ColumnDefinition Width="60" />
            <ColumnDefinition Width="60" />
            <ColumnDefinition Width="60" />
        </Grid.ColumnDefinitions>
       
        <!-- 최상단 행을 위한 내부 그리드 정의출력텍스트박스, BACK버튼, Clear버튼 -->
        <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="120" />
                <ColumnDefinition Width="50*" />
                <ColumnDefinition Width="50*" />
            </Grid.ColumnDefinitions>

            <!-- ViewModel 클래스의 DisplayText 속성과 바인딩 -->
            <Border BorderThickness="1" BorderBrush="Black">
                <TextBlock FontSize="15" VerticalAlignment="Center"
                           HorizontalAlignment="Center"                          
                       Text="{Binding DisplayText,Source={StaticResourcecalcViewModel}}" />
            </Border>


            <!-- 버튼의 Command 이벤트에 Command명을 지정하고 바인딩-->
            <!-- ViewModel 클래스에서 DeleteCharCommand 속성이 정의되야 하고 -->
            <!-- 실제 버튼이 눌러졌을 때 Command에 대한 이벤트 핸들러를 정의해야 한다.-->
            <Button Content="BACK"
              Command="{Binding DeleteCharCommand,Source={StaticResourcecalcViewModel}}"
              Grid.Column="1"/>
            <Button Content="Clear"
              Command="{Binding ClearCommand,Source={StaticResource calcViewModel}}"
              Grid.Column="2"/>
        </Grid>

        <Button Content="1"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="1"
            Grid.Row="1" Grid.Column="0" />

        <Button Content="2"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="2"
            Grid.Row="1" Grid.Column="1" />

        <Button Content="3"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="3"
            Grid.Row="1" Grid.Column="2" />
        <Button Content="+"
            Command="{Binding OperationCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="+"
            Grid.Row="1" Grid.Column="3" />

        <Button Content="4"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="4"
            Grid.Row="2" Grid.Column="0" />

        <Button Content="5"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="5"
            Grid.Row="2" Grid.Column="1" />

        <Button Content="6"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="6"
            Grid.Row="2" Grid.Column="2" />
        <Button Content="-"
            Command="{Binding OperationCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="-"
            Grid.Row="2" Grid.Column="3" />

        <Button Content="7"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="7"
            Grid.Row="3" Grid.Column="0" />

        <Button Content="8"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="8"
            Grid.Row="3" Grid.Column="1" />

        <Button Content="9"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="9"
            Grid.Row="3" Grid.Column="2" />
        <Button Content="*"
            Command="{Binding OperationCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="*"
            Grid.Row="3" Grid.Column="3" />

        <Button Content="0"
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="0"
            Grid.Row="4" Grid.Column="0" />

        <Button Content="."
            Command="{Binding AddCharCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="."
            Grid.Row="4" Grid.Column="1" />

        <Button Content="="
            Command="{Binding CalcCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="="
            Grid.Row="4" Grid.Column="2" />
        <Button Content="/"
            Command="{Binding OperationCommand,Source={StaticResource calcViewModel}}"
            CommandParameter="/"
            Grid.Row="4" Grid.Column="3" />
    </Grid>
</Window>
n  CalcViewModel.cs
using System;
using System.ComponentModel;
using System.Windows.Input;

namespace Calc
{   
    public class CalcViewModel : INotifyPropertyChanged
    {
        //아래 두 필드는 속성으로 구현되어 있다.
        //출력될 문자들을 담아둘 변수
        string inputString = "";

        //계산기화면의 출력 텍스트박스에 대응되는 필드
        string displayText = "";

        //속성이 바뀔때 이벤트 발생하도록 이벤트 정의
        public event PropertyChangedEventHandler PropertyChanged;

        //생성자
        public CalcViewModel()
        {
            //이벤트 핸들러 정의
            //숫자 버튼을 클릭할 때 실행
            this.AddCharCommand = new AddCharCommand(this);

            //백스페이스 버튼을 클릭할 때 실행한글자 삭제
            this.DeleteCharCommand = new DeleteCharCommand(this);

            //Clear 버튼을 클릭할 때 실행출력창을 전부 지운다.
            this.ClearCommand = new ClearCommand(this);

            //+,-,*,/ 버튼을 클릭할 때 실행
            //현재출력창의 숫자를 Op1 속성에 저장, Op속성에 클릭한 연산자 저장
            //계산기의 출력화면을 Clear
            this.OperationCommand = new OperationCommand(this);

            // =버튼을 클릭시 실행
            this.CalcCommand = new CalcCommand(this);
        }

        // Public 속성들을 정의
        public string InputString
        {
            internal set
            {               
                if (inputString != value)
                {
                    inputString = value;
                    OnPropertyChanged("InputString");
                    this.DisplayText = inputString;
                    ((DeleteCharCommand)this.DeleteCharCommand).OnCanExecuteChanged();
                }               
            }

            get { return inputString; }
        }

        //계산기의 출력창과 바인딩된 속성
        public string DisplayText
        {
            protected set
            {
                if (displayText != value)
                {
                    displayText = value;
                    OnPropertyChanged("DisplayText");
                }
            }
            get { return displayText; }
        }

        public string Op { getset; }
        public double Op1 { getset; }
        public double Op2 { getset; }

        // 숫자 클릭
        public ICommand AddCharCommand { protected setget; }

        // <- 클릭한글자씩 삭제
        public ICommand DeleteCharCommand { protected setget; }

        // C 클릭시 DisplayText 전체를 지운다.
        public ICommand ClearCommand { protected setget; }

        // +, -, *, / 클릭
        public ICommand OperationCommand { protected setget; }

        // = 클릭
        public ICommand CalcCommand { protected setget; }


        protected void OnPropertyChanged(string propertyName)
        {
            //이벤트를 발생시킨다.
            if (PropertyChanged != null)
                PropertyChanged(thisnew PropertyChangedEventArgs(propertyName));
        }
    }

    // CanExecute를 호출하기 위한 메소드
    // 예를들면
    // 처음 화면이 뜰때 BACK 버튼이 비활성화 되었다가
    // 입력이 들어오묜 활성화 되는때 이 메소드를 호출한다.
    public interface IBaseCommand : ICommand
    {
        void OnCanExecuteChanged();
    }

    class AddCharCommand : ICommand
    {
        private CalcViewModel viewModel;
        public event EventHandler CanExecuteChanged;

        public AddCharCommand(CalcViewModel viewModel)
        {
            this.viewModel = viewModel;
        }
        public bool CanExecute(object parameter)
        {
            return true;
        }
        // 1,2,,,, 숫자들을 눌렀을때 실행됨
        public void Execute(object parameter)
        {
            viewModel.InputString += parameter;                       
        }       
    }

    class DeleteCharCommand : IBaseCommand
    {
        private CalcViewModel viewModel;

        // OnCanExecuteChanged 메소드의
        // ommandManager.InvalidateRequerySuggested()를 호출하면
        // CanExecuteChanged 이벤트가 호출되어
        // CanExecute로 해당 Command가 있는 버튼을 활성화 또는 비활성화
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested += value; }
        }       
        public DeleteCharCommand(CalcViewModel viewModel)
        {
            this.viewModel = viewModel;
        }
        public bool CanExecute(object parameter)
        {           
            return viewModel.InputString.Length > 0;
        }
        // BACK 버튼을 눌렀을 때 실행됨
        public void Execute(object parameter)
        {
            viewModel.InputString = viewModel.InputString.Substring(0, viewModel.InputString.Length - 1);
        }
        public void OnCanExecuteChanged()
        {
            CommandManager.InvalidateRequerySuggested();
        }
    }

    class ClearCommand : IBaseCommand
    {
        private CalcViewModel viewModel;

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested += value; }
        }

        public ClearCommand(CalcViewModel viewModel)
        {
            this.viewModel = viewModel;
        }
        public bool CanExecute(object parameter)
        {
            return viewModel.InputString.Length > 0; ;
        }
        public void Execute(object parameter)
        {
            // Clear
            viewModel.InputString = "";
        }
        public void OnCanExecuteChanged()
        {
            CommandManager.InvalidateRequerySuggested();
        }
    }

    class OperationCommand : IBaseCommand
    {
        private CalcViewModel viewModel;

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested += value; }
        }

        public OperationCommand(CalcViewModel viewModel)
        {
            this.viewModel = viewModel;
        }
        public bool CanExecute(object parameter)
        {
            return viewModel.InputString.Length > 0;
        }
        public void Execute(object parameter)
        {
            viewModel.Op = parameter.ToString();
            viewModel.Op1 = Convert.ToDouble(viewModel.InputString);
            viewModel.InputString = "";
        }
        public void OnCanExecuteChanged()
        {
            CommandManager.InvalidateRequerySuggested();
        }
    }

    class CalcCommand : IBaseCommand
    {
        private CalcViewModel viewModel;

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested += value; }
        }

        public CalcCommand(CalcViewModel viewModel)
        {
            this.viewModel = viewModel;
        }
        public bool CanExecute(object parameter)
        {
            return (viewModel.Op1.ToString() != string.Empty
                    && viewModel.Op2.ToString() != string.Empty);
        }
        public void Execute(object parameter)
        {
            viewModel.Op2 = Convert.ToDouble(viewModel.InputString);

            switch (viewModel.Op)
            {
                case "+": viewModel.InputString = (viewModel.Op1 + viewModel.Op2).ToString(); break;
                case "-": viewModel.InputString = (viewModel.Op1 - viewModel.Op2).ToString(); break;
                case "*": viewModel.InputString = (viewModel.Op1 * viewModel.Op2).ToString(); break;
                case "/": viewModel.InputString = (viewModel.Op1 / viewModel.Op2).ToString(); break;
            }
            viewModel.Op1 = Convert.ToDouble(viewModel.InputString);
        }
        public void OnCanExecuteChanged()
        {
            CommandManager.InvalidateRequerySuggested();
        }
    }

}

n  실행결과
 066117be0ad9045c67d53e9da88866cf_1482335