블로그 이미지
* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/ kaki104

카테고리

List All (551)
Xamarin Forms (4)
Bot Framework (19)
Azure (9)
Windows 10 (35)
Facebook News & Tips (158)
Windows App(Universa.. (83)
Windows 8&8.1 (113)
Windows Phone 8 (42)
Silverlight (37)
HTML5 & MVC4 (16)
WPF (1)
Portable Class Library (2)
Uncategorised Tips a.. (3)
Kinect for Windows (2)
ETC (12)
kaki104 Scrap (4)
App News (11)
Total521,317
Today36
Yesterday108


나만의 AI Speaker 만들기


라즈베리파이, UWP, Microsoft Azure 서비스를 이용해서 한글을 지원하는 AI Speaker를 만드는 과정을 설명드릴려고 합니다.

총 9개의 동영상으로 구성할 예정입니다.



Part1

. Smart Speaker, AI Speaker란
. AI Speaker 종류(국내, 해외)
. AI Speaker 관련 기사 및 사이트
. System diagram
. Microsoft Harman Kardon Invoke with Cortana
. Microsoft Suface Headphone
. 준비물

. Part1 바로가기



Part2

. Bot 생성 및 배포
. NuGet packages설치
. Azure에 Publish
. Channel 생성 및 연결
. DirectLine 추가
. Bot 연결 테스트
. Part2 바로가기


. Part2까지 소스 - 모든 개발이 완료되면 전체 소스를 Git에 업로드하도록 하겠습니다.

KakiAISpeaker.Bot_part2.zip


Part3

Part4

Part5

Part6

Part7

Part8

Part9


Posted by MVP kaki104

페이스북 그룹에 올려주신 문의 내용에 맞는 셈플을 만들어 보았습니다.
https://www.facebook.com/groups/w10app 



Q. 안녕하세요.
숫자 키패드에 마우스 클릭이나 키보드 둘 다 입력이 가능하도록 mvvm을 사용하여 구현하고 싶습니다.
기존 event-driven에서는 두 개의 event를 구현해서 button에 연결하면 되었는데,이를 mvvm으로 하려니 문제가 생겼네요.
제가 알기로는 mvvm하에서는 xaml상에서 버튼 컨트롤에 command로 연결해줘야 하는 것으로 알고 있습니다. 즉 버튼 컨트롤에 하나의 이벤트만 커맨드로 처리할 수 있다고 저는 알고 있는데, 이러면 이벤트 두 개 중 하나만 구현 가능한 건가요?
mvvm하에서도 event-driven과 같이 마우스 클릭이나 키보드 둘 다 사용 가능하게 구현하고 싶은데, 이를 어떻게 구현해야 하나요?



A. 버튼에 단축키를 설정하면 간단하게 해결하실 수 있습니다.


참고

https://docs.microsoft.com/en-us/windows/uwp/design/input/keyboard-accelerators


                <!--숫자 키패드는 키를 추가해줘야 합니다.-->
                <Button Grid.Column="0" Grid.Row="0" Content="1"
                        Command="{Binding InputCommand}" CommandParameter="1">
                    <Button.KeyboardAccelerators>
                        <KeyboardAccelerator Key="Number1" />
                    </Button.KeyboardAccelerators>

                </Button>


1버튼에 숫자키1를 단축키로 설정하고, InputCommand를 실행 합니다. 실행할 때 CommandParameter로 1을 넘겨 줍니다.



        private void Init()
        {
            InputNumbers = "0";
            InputCommand = new RelayCommand<object>(ExecuteInputCommand);
        }

        /// <summary>
        ///     인풋 커맨드 실행
        /// </summary>
        /// <param name="obj"></param>
        private void ExecuteInputCommand(object obj)
        {
            if (!(obj is string number)) return;

            
            var num = int.Parse(InputNumbers.Replace(",", ""));

            //backspace키는 shell에서 사용하고 있기 때문에 사용이 않되는 듯..
            switch (number)
            {
                case "*":
                    break;
                case "B":
                    num = num.ToString().Length == 1
                        ? 0
                        : int.Parse(num.ToString().Substring(0, num.ToString().Length - 1));
                    break;
                default:
                    num = int.Parse(num + number);
                    break;
            }

            InputNumbers = string.Format("{0:N0}", num);
        }


InputNumbers라는 프로퍼티에 숫자를 string.Format을 이용해서 변환을 해서 집어 넣습니다.


그러면 3자리마다 컴마가 입력됩니다. 숫자 FormatString에 대한 자세한 사항은 검색을 이용하면 쉽게 찾으실 수 있습니다.


BackSpace키는 쉘에서 네비게이션 Back을 하는 키로 사용되고 있어서 B키를 하나 지우는 키로 사용했습니다. 


Windows Tempalte Studio를 이용해서 만든 앱이 아니라면, 사용이 가능할 것이라고 생각됩니다.


자세한 내용은 소스를 참고하세요


깃허브 소스

https://github.com/kaki104/BasicSamples


Posted by MVP kaki104


오랜만에 포스트를 작성하네요. 음..변명을 하자면.. 챗봇 공부를 하고 있는 중이였는데 Build 2018 동영상이 나와서 그것 좀 보다가..끝나고 나니..뭘해야할지..막막


사실 Windows ML을 하려고 했으나, 머신 러닝을 위해서는 파이선을 공부해야 한다고 해서 한 몇일 고민하다가.. 일단 파이선 공부는 뒤로 미루고, Build에서 발표된 새로운 UWP에 기능에 대해서 집중하기로 마음을 먹고.. 마음의 위안을 삼은체 탱자 탱자 하다가.. 오늘에서야 ...ㅋㅋㅋ



하지만, 오늘 대박 소식을 전하려고 합니다. 그동안 UWP의 숙원 사업(?) 중에 하나가 사용자의 허가를 받지 않은 로컬 폴더와 파일의 목록을 조회하고, 열어서 가지고 오는 것이 있었습니다.


이 부분이 않되어서 참 많은 어려움이 있었죠..하지만, 이번 Build에서 드디어 추가되었습니다~ 와~~~ 그러면 자세히 알아 보도록 하겠습니다.



1. 참고

https://docs.microsoft.com/en-us/windows/uwp/files/file-access-permissions

https://github.com/Microsoft/AppModelSamples



2. BroadFileSystemAccess


이 녀석이 그 녀석입니다. 사용자의 허가(앱을 설치할 때)를 받으면 그 이후 부터는 폴더와 파일에 접근할 때 별도의 허가 없이도 가능합니다. 하지만, 이 녀석을 사용하기 위해서는 선행 조건이 있습니다.


UWP 앱 Target, Min 버전이 17134이여야 합니다.

또한, Windows 10 버전도 1803 버전이여야 합니다.

* 물론 Visual Studio 최신 버전이 필요하고, Windows SDK도 최신 버전이 필요합니다.

이 두가지 조건에 만족한다면, 바로 사용이 가능하며, 추가로 약간 귀찮은 작업을 해줘야 합니다.


Capability의 기능이기 때문에 Package.appxmanifest에 정의를 해줘야 하는데...

GUI 화면에서는 이 녀석을 찾을 수가 없습니다. (현재는.. 추후 추가될 것이라고 생각됩니다만..) 그래서, Package.appxmanifest 파일을 xaml editer로 열어서 수동 편집해 주어야 합니다.


<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap mp uap5 rescap">


...


  <Capabilities>
    <Capability Name="internetClient" />
    <rescap:Capability Name="broadFileSystemAccess" />
  </Capabilities>




3. C:/ 폴더와 서브 폴더 목록을 가지고와 볼까요?


var rootFolder = await StorageFolder.GetFolderFromPathAsync(@"c:\");


이렇게 코딩하면 바로 c:/ 루트 폴더를 가지고 올 수 있습니다. 아무것도 묻거나 따지지 않습니다~ 여기가 바로 신세계입니다~ 


서브 폴더는 어떻게 가지고 오냐구요?

그건 이전과 동일하게, GetFoldersAsync()를 이용하면 됩니다.


        private async void GetSubDirectories(StorageFolder folder, TreeViewNode folderNode, int depth = 0)
        {
            try
            {
                if (depth > 1) return;
                var subDirs = await folder.GetFoldersAsync();
                if (subDirs.Any() == false || folderNode.Children.Any()) return;
                foreach (var subDir in subDirs)
                {
                    var subDirNode = new TreeViewNode
                    {
                        Content = new DirectoryModel
                        {
                            Name = subDir.Name,
                            Path = subDir.Path,
                            HasSubDirectory = false
                        },
                    };
                    GetSubDirectories(subDir, subDirNode,depth + 1);
                    folderNode.Children.Add(subDirNode);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }



4. WPF 프로그램을 UWP로 대체하는 날이 얼마 남지 않은 듯 합니다.


다만, 걱정은 우리나라 WPF 개발 시장과 개발자의 인식이 좀.. 거시기 하다는.. 흑흑..

왜 아직도 윈폼으로 개발하고 있나요..엉엉(물론 지금 제가 진행하는 프로젝트도 WPF 개발자를 구하지 못해서 방황하는 중이지만..) 그래도 이제는 WPF 더 나아가서 UWP 프로젝트가 마니 생기기를..


당분간 새로 추가된 기능들을 아래 소스 폴더에 정리할 예정입니다.



5. 소스


https://github.com/kaki104/UWP_17134



PS. 27일날 갑자기 방문자수가 500을 넘게 찍었던데 무슨일이 있었떤 거죠??



6. 질문 주신 내용에 대한 소스 추가 합니다.


DownloadsFolder.CreateFileAsync
DownloadsFolder.CreateFolderAsync

를 사용하면 파일 생성은 가능하지만 이미 생성된 파일이나 폴더가 있을 경우 get 할 수 있는 OpenIfExists 같은 CollisionOption 을 사용할 수가 없네요. BroadFileSystemAccess 을 사용해도 마찬가지 인것 같고요

picker 를 이용하지 않고 UWP 사용자 폴더의 파일이나 폴더에 접근하여 가져오고 데이터를 쓰고 하는 다른 방법이 있을까요?


6-1. Create


        private async void CreateFileInSelectedFolder()
        {
            if (_selectedFolder == null) return;
            var file = await _selectedFolder.CreateFileAsync("TextFile.tmp", CreationCollisionOption.OpenIfExists);
            if (file == null) return;
            var msg = new MessageDialog("Successful creation or opening operation");
            await msg.ShowAsync();
        }



6-2. Open


        private async void OpenFile()
        {
            if (_selectedFolder == null) return;
            try
            {
                var file = await _selectedFolder.GetFileAsync("TextFile.tmp");
                if (file == null) return;
                var msg = new MessageDialog("Successful opening operation");
                await msg.ShowAsync();
            }
            catch (FileNotFoundException ffe)
            {
                var msg = new MessageDialog(ffe.Message);
                await msg.ShowAsync();
            }
            catch (Exception)
            {
                throw;
            }
        }


문의하신 내용에 대한 답변이 되었는지 모르겠습니다. 추가로 궁금하신 사항은 다시 적어주세요 감사합니다.


소스도 올려 놓았으니 참고하세용


Posted by MVP kaki104


이번 포스트는 얼마전 대한민국 정부에서 AI 서비스 개발을 지원하기 위해 오픈한 AI 오픈 이노베이션 허브에서 제공하는 한글 음성 인식 기능을 이용해서 한글 인식을 하는 방법에 대한 내용입니다.


개발 가이드를 보면 Java, PHP, C++, Python Node.js를 이용한 예제가 존재 합니다.  그런데, C# 예제가 존재 하지 않아 직접 삽질을 했습니다.


이 API는 상업용 목적으로 사용하기 위해서는 기술 이전을 받아야 하고, 일반 업무용 목적의 사용이라면, 1일기준 제한된 범위에서 특별한 제약이 없이 사용이 가능하다고 합니다.


우선 이런 좋은 서비스를 Open API 형태로 제공해 준 여러 관계자 분들께 감사드리고 싶습니다. 이 API를 이용하면 좀더 쉽게 한글 음성 인식을 지원하는 앱 개발이 가능할 것 같습니다. 


동영상을 보시기 전에 채널 구독 먼저 부탁드립니다~ 유튜브 채널 바로가기



PPT


aihub.pptx


Posted by MVP kaki104



이번 강좌는 지난번에 만들었던 영어 단문 발음 연습 앱에 TTS 기능을 추가해서 좀더 효과적인 학습앱 개발을 하는 것 입니다.

TTS는 글씨를 음성으로 변경해서 스피커를 통해서 들려주는 서비스로, 우리 주위에서 상당히 많이 사용되고 있는 기술 입니다. Windows에서는 기본적으로 한글 음성 서비스를 지원하고 있기 때문에 손쉽게 이런 기능을 구현 할 수 있습니다.



유튜브 채널 구독 신청 plz~



* 라즈베리파이3에 한국어 음성 파일 설치하기




완성 앱 데모







Part 1


* 환경 및 준비
* 참고 자료
* TTS, Text-To-Speech Service
* TTS, Text-To-Speech
* SSML Element
* TTS - Demo
* 영어 단문 발음 연습 앱 V2
* PC 환경 설정 확인
* 앱 개발 순서
* 음성 출력 방법
* 단문 발은 연습 페이지 구현 로직




Part 2


* 단문 초기화 기능 구현
* cvs 파일 프로젝트에 추가
* 단문 헬퍼 파일 추가, 구현
* CommonHelper 추가, 구현
* Singleton을 이용해서 싱글톤 인스턴스 만들어서 사용하기




Part 3


* 단문 연습 페이지 구현 - 시작 버튼 클릭 시 단문 하나 선택 하기 구현
* MainPage.xaml 화면 구현
* MainViewModel.cs 구현
- 커맨드 추가
- ShowText, Result 프로퍼티 추가 및 디자인 타임 데이터 연결
- 화면에 바인딩
- 화면에 MediaElement 컨트롤 추가
* Blend를 이용해서 커맨드와 MediaElement 연결
* MainPage.xaml 화면 추가 구현
* MainViewModel.cs 추가 구현
- Init() 구현
- NavigationServiceEx 인스턴스 가지고 와서 이벤트 연결
- NavigationService_Navigated 이벤트 핸들러 구현
- 시작 버튼 클릭 시 단문 하나 선택하기 구현




Part 4


* 단문 연습 페이지 구현 - 음성 출력 구현
* MainViewModel.cs 추가 구현
- SpeechSynthesizer 인스턴스 생성 및 초기화
- 음성 스트림 생성
- Voice 목록에서 한국어, 영어 두개의 voice 찾아서 사용
- 음성 스트림 출력
* MediaBehavior 추가 및 구현
* Blend를 이용해서 MediaBehavior를 MediaElement와 연결
* MediaElement에 바인딩 수정




Part 5


* 단문 연습 페이지 구현 - 음성 입력 받기와 결과 표시
* MainViewModel.cs 에 음성 입력 받기 구현
- MediaEndedCommand가 실행 된 후 로직 구현
- RecognizeWithUIAsync를 사용해서 음성 입력 받기
- UIOptions 수정




Part 6


* 단문 연습 페이지 구현 - 틀렸을 경우 처리와 반복 학습 처리 구현
* MainViewModel.cs 추가 구현
- HasStart 프로퍼티로 변경
- 음성 스트림 생성 부분 메소드로 변경
- 한국어일 때와 영문일 때 음성 스트림 생성 방법 다르게 구현
- 음성 입력 부분 메소드로 변경
- 틀렸을 때 영문 음성 출력이 되도록 구현(SSML 사용)
- 영문 음성 시작전 1초의 딜레이 추가
- 반복 학습을 위해 랜덤 단어 선택 부분을 메소드로 변경




Part 7


* 단문 연습 페이지 구현 - 종료 버튼 처리
* Target Version을 변경해서 Property Maker를 이용한다.
* MainPage.xaml 화면 추가 구현
- BoolToVisibilityConverter를 추가해서 버튼 보이기/숨기기 작업




PPT


iot-tts.pptx



Posted by MVP kaki104



IoT Core에서 동작하는 Speech Recognition에 대한 내용입니다.


ppt작성, 코딩, 촬영, 편집까지.. 시간이 많이 걸리내요.. 아침에 일어나서 바로 시작한 작업인데..밤새고 새벽에..쿨럭..

음성 인식에 대해서 처음 접하시는 분들이 보시고 이해하실 수 있으면 좋겠습니다. 


앞으로 지속적으로 음성 인식과 연결된 주제에 대해서 동영상을 만들려고 합니다. 그 끝에는 어떤 것이 있을까요?

높은 산의 꼭데기만 보고 뛰어서 올라가면 힘이 마니 듭니다. 하지만, 산 아래에서 부터 천천히 꾸준히 올라간다면, 아무리 높은 산이라도 정복 할 수 있습니다. 그러니, 모두 함께 천천히 올라갔으면 좋겠습니다.


마지막, 한가지 작은 부탁이라면, 유튜브 구독자가 좀더 늘었으면 하는..후후

유튜브 채널 바로가기






Part 1


* 환경 및 준비
* 참고 자료
* Speech Recognition Constraints
* Speech Recognition 기초
* SpeechRecognizer
* List of speech recognition supported languages




Part 2


* 영어 말하기 연습 앱 개발
* PC 환경 설정 확인
* 앱 개발 순서
* 프로젝트 생성
* 세팅




Part 3


* 영어 단문을 CSV 파일로 생성
* 생성한 파일 프로젝트 추가하고 빌드시 앱 설치 폴더에 복사되도록 설정
* 파일을 읽어서 ShellPage CaseList 프로퍼티에 추가
* GitHub에 Project생성
* To-do 등록 - issues로 변경

* 브랜치 생성

* PR 생성




Part 4


* 기본 연습 페이지 구현 시작
* MainPage.xaml.cs 코딩
- SpeechAndTTS 셈플 프로젝트 중 Scenario_ListConstraint의 코드를 복사해서 붙여 넣는 방법으로 기본 작업
- OnNavigateTo 코딩
- AudioCapturePermissions 클래스 복사
- InitializeRecognizerAsync 코딩
- CommonHelper 클래스 추가, ShowMessageAsync 추가




Part 5


* 기본 연습 페이지 화면 구현 시작 MainPage.xaml
* MainPage.xaml.cs
- ButtonBase_OnClick 구현
- _speechRecognizer_StateChanged 구현
* 화면 테스트
- ButtonBase_OnClick 수정 : 실패인 경우 메시지 추가
* 라즈베리파이3에 배포 테스트



Part 6

* 심화 연습 페이지 구현
* MainPage.xaml.cs에
- OnNavigatedFrom 구현
- Cleanup 수정
* PredefindedPage.xaml
- MainPage.xaml 디자인 복사
* PredefindedPage.xaml.cs
- field 복사
- MainPage.xaml.cs 코드 복사 후 수정
- InitializeRecognizerAsync 수정
- ButtonBase_OnClick 수정
- ContinuousRecognitionSession_Completed 구현
- _speechRecognizer_HypothesisGenerated 구현
- ContinuousRecognitionSession_ResultGenerated 구현



Part 7

* 심화 연습 페이지 구현
* PredefindedPage.xaml.cs
- _timer 추가 구현
* 테스트
* 라즈베리파이3에 배포 테스트
* 버그 수정
* 마침말



PPT




Posted by MVP kaki104



이번 포스트 주제는 Windows 10 IoT Core - Hello World 입니다.

IoT를 처음 시작하시려는 분들을 위한 포스트로, 자세하게 설명하고 있습니다. 앞으로 동영상의 방향은 IoT를 이용한 여러가지 앱을 만들어서 응용하는 방향으로 진행할 예정입니다.


많은 구독 신청 부탁드립니다.



Part1


*Why Windows 10 IoT Core?
Windows 10 IoT Core Compatible Boards
Raspberry Pi 3 kits
What can you make?
라즈베리파이에 윈도우 설치 및 설정
해상도 설정 참고 자료





Part2


Hello World Windows 10 IoT Core




PPT


iot-helloworld.pptx


Posted by MVP kaki104



이번 포스트는 GitHub와 VS를 이용해서 어떻게 프로젝트를 관리하는가에 대한 내용입니다.

5개의 part로 구분되어 있으며, 각 part별 내용은 바로 상단에 있으니 필요한 내용을 바로 찾아서 보실 수 있을 것 같습니다.

앞으로 GitHub를 이용해서 오픈 소스 프로젝트를 진행하기 위한 준비 단계이니 꼭~ 참고해 주세요


혹시 내용 중 수정 사항은 이곳에 리플로 남겨주시거나 메일로 알려주시면 수정하도록 하겠습니다.


ps. diablo3hub앱은 빌드 후 실행 가능하게 수정하도록 하겠습니다.

-> 수정 완료했습니다.


Part1
환경 및 준비
참고 자료
What is GitHub?
Why git for developer
GitHub 가입




Part2
GitHub Flow - Create a branch
GitHub Flow – Add commits
GitHub Flow – Open a Pull Request
GitHub Flow – Discuss and review your code
GitHub Flow – Deploy
GitHub Flow – Merge




Part3
GitHub – New repository
GitHub – Project 추가
GitHub – Extension download and install
UWP 프로젝트 추가, 커밋, 싱크




Part4
GitHub – Collaborators 추가
GitHub – Clone repository
GitHub – VS와 연동 작업




Part5
GitHub - Fork 후 작업하기




PPT


GitHub와VS연동작업.pptx


Posted by MVP kaki104
페이스북에 올라온 민원 해결을 위해서 간단하게 프로젝트를 만들었습니다.

Q. 텍스트박스에 숫자를 입력하면 자동으로 컴마를 찍어주고, 백스페이스를 누르면 삭제가 되도록 하고 싶습니다.~

A. 일단 여러분들이 의견 주셨습니다.

우선 컨버터를 이용한 방법이 이야기가 되어서, 저도 컨버터를 이용해서 처리를 할려고 해봤는데..

컨버터는 프로퍼티 체인지 이벤트가 발생했을 경우에 컨버터가 값을 변경해 주는 역할을 합니다...그런데.. TextBlock에는 뷰모델에서 변경된 내용을 바로 화면에 이쁘게 뿌려주는데.. 텍스트박스에서는 키가 입력되면, 그 내용을 바로 뷰모델에 값을 넣어주는 역할만을 하고, 프로퍼티가 변경된 내용을 화면에 다시 뿌려주지는 않습니다.

StringFormatConverter.cs

using System;
using Windows.UI.Xaml.Data;
namespace App1
{
    public class StringFormatConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            var format = parameter as string;
            if (!string.IsNullOrEmpty(format) && value is string)
            {
                int.TryParse(value.ToString(), out var number);
                return string.Format(format, number);
            }
            return value;
        }
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            if (value == null) return null;
            int.TryParse(value.ToString().Replace(",", ""), out var number);
            return number.ToString();
        }
    }
}

음..그래서 결국 비헤이비어를 만들어서 처리를 해보았습니다.

NumberTextBoxBehavior.cs

using Windows.System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Microsoft.Xaml.Interactivity;
namespace App1
{
    public class NumberTextBoxBehavior : Behavior<TextBox>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.KeyUp += AssociatedObject_KeyUp;
        }
        private void AssociatedObject_KeyUp(object sender, KeyRoutedEventArgs e)
        {
            switch (e.Key)
            {
                case VirtualKey.Number0:
                case VirtualKey.Number1:
                case VirtualKey.Number2:
                case VirtualKey.Number3:
                case VirtualKey.Number4:
                case VirtualKey.Number5:
                case VirtualKey.Number6:
                case VirtualKey.Number7:
                case VirtualKey.Number8:
                case VirtualKey.Number9:
                case VirtualKey.Back:
                    var numberText = AssociatedObject.Text;
                    if (string.IsNullOrEmpty(numberText)) return;
                    var number = int.Parse(numberText.Replace(",", ""));
                    var formatString = string.Format("{0:N0}", number);
                    if (formatString != number.ToString())
                    {
                        AssociatedObject.Text = formatString;
                        AssociatedObject.SelectionStart = AssociatedObject.Text.Length;
                    }
                    break;
            }
        }
        protected override void OnDetaching()
        {
            AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
            base.OnDetaching();
        }
    }
}


MainPage.xaml


<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:Custom="using:Microsoft.Xaml.Interactivity"
    x:Class="App1.MainPage"
    xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters"
    mc:Ignorable="d"
    x:Name="mainPage">
    <Page.Resources>
        <local:StringFormatConverter x:Key="StringFormatConverter" />
    </Page.Resources>
    <Page.DataContext>
        <local:MainPageViewModel />
    </Page.DataContext>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <TextBox MinWidth="200" TextAlignment="Right"
                     Text="{Binding Number, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                <Custom:Interaction.Behaviors>
                    <local:NumberTextBoxBehavior />
                </Custom:Interaction.Behaviors>
            </TextBox>

            <TextBlock Text="{Binding Number}" />
            <Button Click="ButtonBase_OnClick" />
        </StackPanel>
    </Grid>
</Page>


결과 화면입니다.



파일

NumberTextBox.zip


Posted by MVP kaki104
TAG Behavior, UWP

DependencyProperty의 개념 소개 및 사용 방법에 대한 포스트 입니다.



Dependency Property와 Attached Property의 차이점이 뭐지? part0

Dependency Property와 Attached Property의 차이점이 뭐지? part1




이미 이전 part1이 공개되었는데.. 사실은 이 포스트가 먼저 작성이 되어야 하는 것이였네요..그래서 part0입니다. 우선 어려운 주제를 다루기에 앞서 이야기를 하나 풀어 보겠습니다.



사람과 사람은 서로 공통점과 차이점이 존재합니다. 차이점에는 얼굴 크기 모양, 눈 컬러, 머리카락 길이 등이 있고, 공통점에는 손가락 10개, 눈 2개, 머리 1개 등의 정보들이 있습니다. 공통적인 정보들은 대부분 평범한 내용들로 구성됩니다.


그런데 말입니다. 누군가 당신한테 인간의 유전자 수는 몇개 인가요? 라고 물어 본다면 당신은 그 질문의 대답을 어디서 가지고 올까요? 어떤 사람은 유전자 수를 종이에 적어서 뒷 주머니에 넣고 다니고 있어서, 그 질문을 하면 바로 찾아서 알려줄 수 있을 것 입니다. 하지만, 일반적으로 그런 정보를 종이에 적어서 가지고 다니는 사람은 없을 것이라는 생각이 드네요


만약, 그런 사소한 정보들까지 모두 가지고 다녀야 한다면, 아마도 제 뒷주머니의 크기는 아주 큰 백과사전이 들어갈 수 있을 정도가 되어야 할지도 모릅니다. 


그래서, 누군가가 이런 아이디어를 내 놓습니다. 인간에 대한 공통적인 정보는 대부분은 동일하며, 거의 변하지 않는다. 그렇다면, 그런 정보들을 한 곳에 저장해 놓고 찾아서 보면 되지 않을까? 그리고, 예외적인 정보만 종이에 적어서 뒷 주머니에 넣고 다니면서 본다면??

그래서, 사람에 대한 공통적인 정보는 공용 저장소에 저장하고 예외적인 정보는 로컬 저장소에 저장하게 되었다는...이야기가...쿨럭;; (참고 포스트 중 일부를 인용했습니다.)



0. 참고


What is a dependency property?

Dependency Properties

Dependency properties overview


1. 개요


DependencyProperty직역하면 종속속성이라고 합니다. 이 속성을 사용하기 위해서는 DependencyObject를 상속 받은 클래스나 컨트롤에서만 사용이 가능합니다. 이 녀석은 WPF(Windows Presentation Foundation)에서 처음 등장했으며, 이 후 Silverlight, UWP 앱 등 XAML을 기반으로 하는 개발 환경에서 다양하게 사용되고 있습니다. 



2. DependencyProperty 의 기본적인 구성


1) Dependency property: 여기서 이야기 하는 종속속성은 DependencyProperty를 이야기 합니다.


2) Dependency property identifier: 종속속성 식별자는 IsSpinningProperty를 이야기 합니다. 이 식별자는 종속속성의 값을 저장하고, 불러올 때 키 값으로 사용됩니다.


3) CLR(Common Language Runtime) "wrapper": Public bool IsSpinning... 부분을 이야기 하며, 이 종속속성에 값을 넣거나 불러올 때 코드나 XAML에서 실제로 이용하게 됩니다. 그래서, 절대로 내용을 수정하면 않됩니다.


public static readonly DependencyProperty IsSpinningProperty =
    DependencyProperty.Register(
    "IsSpinning", typeof(Boolean),
    typeof(MyCode)
    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}



쉽게 DependencyProperty를 만드는 방법은 Ctrl+K,X를 입력 후에 NetFX30을 선택하시면 선택하는 메뉴가 출력됩니다. part1에 자세한 사항이 나오니 참고하시면 됩니다.



3. DependencyProperty가 GetValue의 동작원리


간단한 예제를 통해서 알아 보도록 하겠습니다.


MainPage.xaml


<Page
    x:Class="PropertySample.Views.MainPage"
    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:commons="using:PropertySample.Commons"
    Style="{StaticResource PageStyle}"
    mc:Ignorable="d">
    <Grid
        x:Name="ContentArea"
        Margin="{StaticResource MediumLeftRightMargin}">

        <Grid.RowDefinitions>
            <RowDefinition x:Name="TitleRow" Height="48"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <TextBlock
            x:Name="TitlePage"
            x:Uid="Main_Title"
            Style="{StaticResource PageTitleStyle}" />

        <StackPanel Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
            <
TextBlock Text="Part0" Margin="10"/>
            <TextBlock Text="Part1" Margin="10"/>
        </StackPanel>

    </Grid>
</Page>


StackPanel 내부에 2개의 TextBlock을 배치했습니다. 너무 붙어있지 못하도록 마진을 10씩 넣었습니다. 겨울이라 서로 멀리 떨어져 있도록...




그런데, TextBlock의 글씨 크기를 더 크게 만들고 싶네요..여기에는 2가지 방법이 있습니다.


하나는 각 TextBlock에 FontSize를 추가하는 일반적인 방법입니다. 물론 스타일로 지정해도 가능합니다.~ 


그렇다면, 다른 하나는??


<Page
    x:Class="PropertySample.Views.MainPage"
    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:commons="using:PropertySample.Commons"
    Style="{StaticResource PageStyle}"
    mc:Ignorable="d" FontSize="30">


Page에 FontSize를 추가하는 것 입니다. 


Page에 FontSize를 추가 했는데..어떻게 TextBlock의 FontSize가 커질까요?? 


이 비밀의 열쇄는 처음에 사람으로 이야기를 했던 부분에 있습니다. 


우선 FontSize를 찾아 내는 방법 입니다.



다음은 FontFamily를 찾아 내는 방법 입니다.



이렇게 GetValue가 호출이 될 때 값을 찾아서 반환하는 것을 resolved dynamically 이라고 합니다.


결과는 다음과 같습니다.


4. DependencyProperty를 사용하면 어떤 장점이 있을까요?


어떤 장점이 있길래 이런 복잡한 방법으로 데이터를 가지고 올까요?


1) 메모리 사용량 감소 : 화면에 모든 컨트롤들이 자신의 프로퍼티 값을 가지고 있다면,, 그 양이 얼마나 커질까요? 하지만, 이런 방법으로 누군가 프로퍼티의 값을 요청하면 찾아보고 알려줄 수 있기 때문에 메모리를 더 적게 사용할 수 있습니다.


2) 값 상속 : 비주얼 트리의 하위 컨트롤들은 상위 컨트롤이 가지고 있는 프로퍼티의 값을 상속 받을 수 있습니다. Style들을 이용해서 다양한 형태로 값을 상속 시킬 수 있습니다.


3) 값 변경 알림 사용 : DependencyProperty는 값이 변경될 때 MVVM pattern에서 처럼 INotifyPropertyChanged 이벤트를 발생 시키며, DataBinding도 연결할 수 있고, Callback을 등록해서 사용할 수 있는 다양한 기능을 제공합니다.



5.  다음 항목들을 참고하세요


사용자 정의 컨트롤을 만드는 방법에 대한 포스트 입니다. Part1~Part4번까지 있습니다.

Custom Control 만들기 Part1



6. 소스

https://github.com/kaki104/PropertySample


Posted by MVP kaki104

티스토리 툴바