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

카테고리

List All (588)
Blazor (1)
Windows App(Universa.. (97)
Xamarin Forms (4)
Bot Framework (19)
Azure (9)
Windows 10 (52)
WPF (5)
Facebook News & Tips (158)
Windows 8&8.1 (113)
Windows Phone 8 (42)
Silverlight (37)
HTML5 & MVC4 (16)
Portable Class Library (2)
Uncategorised Tips a.. (3)
Kinect for Windows (2)
ETC (12)
kaki104 Scrap (4)
App News (11)
Total534,750
Today34
Yesterday70

UWP 앱에서 Cookie 관리하는 방법에 대해서 알아 보도록 하겠습니다.

 

* Cookie
클라이언트 컴퓨터에 저장된 작은 정보입니다.
클라이언트 컴퓨터에 Username, Password, City, PhoneNo 등의 사용자 환경 설정 정보를 저장하는 데 사용됩니다.
Persist Cookie : 만료되는 시간이 없는 지속형 쿠키
Non-Persist Cookie : 만료시간이 존재하는 비 지속형 쿠키

 

* HttpBaseProtocolFilter
Sharing Sessions Between HttpClient and WebViews on Windows Phones
HttpBaseProtocolFilter 클래스는 HttpClient 인스턴스에서 사용하는 기본 필터 또는 처리기를 제공합니다. 추가 필터가 HttpClient 인스턴스에 추가되지 않으면 HttpBaseProtocolFilter 개체가 유일한 필터가됩니다.
HttpBaseProtocolFilter 클래스는 여러 가지 저수준 HTTP 스택 동작을 전환하기위한 속성 집합을 제공합니다.

 

https://youtu.be/cr-sduHHiAs

소스

https://github.com/kaki104/PrismSample2019

Posted by MVP kaki104

Prism으로 시작하는 UWP app Part12
UWP에서 Script 직접 호출과 팝업 처리

UWP 앱에서 Script를 직접 호출하는 방법과 window.alert, window.confirm 등의 팝업 처리에 대해서 알아보도록 하겠습니다.


* InvokeScriptAsync
특정 인수를 사용하여 현재로드된 HTML에 지정된 스크립트 함수를 실행 합니다.
InvokeScript() 메소드는 Windows 8.1 이후 변경되거나 사용할 수 없습니다.
리턴 타입이 string이라는 점을 유의하시기 바랍니다.


* window.alert(), window.confirm() 사용 불가?

UWP의 MessageDialog()를 이용해야 합니다.
Package.appxmanifest - Content URIs
notify를 허용할 Uri 주소를 입력합니다.
window.external.notify()
var messageDialog = new MessageDialog(e.Value);
await messageDialog.ShowAsync();

 

https://youtu.be/ioDI03iXYy0

 

소스 : https://github.com/kaki104/PrismSample2019

Posted by MVP kaki104

WebView - Async, EventAggregator - Prism으로 시작하는 UWP app Part11

 

JavaScript에서 Async 메소드를 호출하고 결과를 처리하는 방법
Windows Runtime Component에서 비동기 메소드를 처리하는 방법
IEventAggregator를 이용해서 UWP나 다른 프로젝트로 이벤트를 넘기는 방법 등에 대해서 다루고 있습니다.

 

* Async : Windows Runtime Component에서 async Task 메소드 사용 방법
* IEventAggregator : 개념 및 사용 방법

 

https://youtu.be/LBS-UJtG2PQ

소스

https://github.com/kaki104/PrismSample2019

Posted by MVP kaki104

WebView 컨트롤에서 JavaScript와 연동을하는 기본적인 방법을 설명합니다.

 

* GitHub에서 소스 다운로드 받고, Branches에서 Part9 소스 싱크하기
* Windows Runtime Component 설명
* Examples

 

https://youtu.be/R89emHtaFvU

 

Posted by MVP kaki104

기존 VS 2017 개발 환경을 VS 2019 환경, Nuget package 업그레이드를 했습니다.
또한, WebView를 추가하고, User-Agent를 변경하여 모바일 브라우저로 인식이 되도록 하는 방법을 설명합니다.

* 개발 환경 설명
* 따라하기 위해서 GitHub에서 소스를 어떻게 받아서 사용하는지 설명
* WebView 페이지 추가
* User-Agent란
* UserAgentHelper 추가하고 사용하기

 

https://youtu.be/pou8078vX2w

 

소스 : https://github.com/kaki104/PrismSample2019

Posted by MVP kaki104

WinForms, WPF 프로젝트에서 Windows 10 API를 사용하는 방법과 MSIX 패키징을 만들어서 배포하는 방법등을 설명합니다.

 

* 환경
* Microsoft.Windows.SDK.Contracts
* Microsoft.Toolkit.Wpf.UI.Controls
* XAML Islands Components Future
* Seamless application deployment, updates, and optimized for DevOps
* MSIX Core
* 트러블슈팅

 

https://youtu.be/oVJJMGlc_Ew


* 소스 :

https://github.com/kaki104/WpfTest

Posted by MVP kaki104

* Prism 앱의 레이어에 대해 설명합니다.


. 재정의 불가능 영역 : Popup, ContentDialog, MediaElement
. 재정의 가능 영역 : 일반 Page
. 기타 영역 : MessageDialog

 

 

 

* 소스 : https://github.com/kaki104/PrismSample

Posted by MVP kaki104


나만의 AI Speaker 만들기


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

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



PDF 등록했습니다!!

AISpeaker.pdf



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

. 클라이언트 프로젝트 추가
. NuGet packages 추가
. MainPage.xaml 코드 추가
. MainViewModel.cs 코드 추가
- DirectLineClient 생성 및 연결
- WebSocketClient 연결
. 클라이언트 실행해서 연결 테스트

- Part3 동영상 바로가기




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

KakiAISpeaker_part3.zip



Part4

* Client 
. 음성 인식 기능 추가
. SRGS.xml 파일 추가
. Direct Line을 이용해서 start 메시지 전달
* Bot
. start 메시지 수신 후 start conversation 메시지 회신

- Part4 동영상 바로가기




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

KakiAISpeaker_part4.zip



Part5
음성명령 녹음하고 전송하기
- 녹음을 위한 MicrophoneHelper추가
- 녹음 시작, 끝내기
- 사용자 음성인지 확인하기
- 저장된 음성 파일 Bot에 전송하기

* ClientStates를 이용한 제어 개요
* ClientStates 변화과정과 관련 소스 살펴보기

- Part5 동영상 바로가기



KakiAISpeaker_part5.zip



Part6

건강이 나빠져서 동영상 제작이 좀 늦어졌습니다. 다음편은 빨리 올리도록 하겠습니다.


* 서비스 추가하기
- Azure
    . Speech Service 추가
    . Storage 추가
- AWS
    . Polly Service 추가
- Part6 동영상 바로 가기



Part7


- 수신된 음성 명령 확인
- Speech Service 헬퍼 추가, 인증 클래스 추가
- Polly Service 헬퍼 추가
- Blob Service 헬퍼 추가
- 결과 클라이언트에 반환하기
- appsetting.json에 키 값 사용하기
- Microsoft.Extension.Http nuget 사용하기

** 소스 : https://github.com/kaki104/KakiAISpeaker

- Part7 : 동영상 바로 가기


Part8

Part9



2019-04-17 업데이트


Visual Studio 2019 기준으로 스크린샷을 다시 만들었습니다.



설치를 완료하기 위해서는 Visual Studio 2019를 재시작 해야합니다.


설치완료 후 Visual Studio 2019를 시작하시고, 시작 창에서 Create a new project를 선택하시고 bot으로 검색을 하시면 아래와 같은 프로젝트 목록을 보실 수 있습니다. 여기서 EchoBot을 선택하시면 될 것 같습니다.



프로젝트 생성 후 IIS로 실행하기를 하니 정상적으로 봇 프로젝트가 실행되는 것을 확인했습니다.

참고하세요


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