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

카테고리

List All (558)
Xamarin Forms (4)
Bot Framework (19)
Azure (9)
Windows 10 (39)
WPF (3)
Facebook News & Tips (158)
Windows App(Universa.. (84)
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)
Total528,590
Today21
Yesterday25



2019년 2월 24일에 공개할 HoloLens 2.0 티저 영상이 올라왔습니다. 영화의 한장면 같은 느낌이네요.


원본 보기


Microsoft는 몇 주 안에 2019 년 Mobile World Congress에서 HoloLens 2.0을 선보일 예정입니다.

오늘 HoloLens 팀의 팀장 인 Alex Kipman은 새로운 Holographic Processing Unit과 현실 세계를 조작 할 수있는 일련의 다각형으로 바꿀 수있는 능력을 암시하면서이 이벤트에 대한 티저 비디오를 게시했습니다.


우리는 이미 다음 HoloLens가 더 많은 인공 지능 기능을 갖춘 개선 된 홀로 그래픽 처리 장치와 향상된 Kinect 형 깊이 카메라를 갖게 될 것임을 알고 있습니다. 보도에 따르면, 최근에 발표 된 Qualcomm Snapdragon XR1 프로세서는 "고품질"VR 및 AR 경험을 제공한다는 단호한 목적으로 설계되었으며 MWC 모양을 설명하는 5G 연결 기능을 제공 할 예정입니다. 또한 더 큰 시야와 더 긴 배터리 수명을 포함하여 HoloLens 1의 문제를 해결할 것으로 보입니다.


유투브 동영상 보기



Posted by MVP kaki104


원본 : 

https://blogs.msdn.microsoft.com/dotnet/2019/01/29/announcing-net-core-3-preview-2/



C# 8

C# 8.0 주요 언어 릴리스입니다. 이 글에서는 Preview 2에서 새로 추가 된 몇 가지 즐겨 찾기에 대해 설명하겠습니다.


Using Declarations

코드의 들여 쓰기가 필요한 명령문을 사용하는 것에 지쳐 있습니까? 더 이상은 없어! 이제 다음 코드를 작성하면 using 문을 현재 명령문 블록의 범위에 첨부 한 다음 객체를 그 끝에 배치합니다. 

--> 들여쓰기를 하지 않아도 된다는 내용 같은데.. 정확한 내용은 원본을 참고 하세요



Switch Expressions

C#을 사용하는 사람은 switch 구문에 대한 아이디어를 좋아하지만 구문은 좋아하지 않을 것입니다. 


C# 8은 스위치 식을 도입하여 다음과 같은 기능을 제공합니다. 

- 간결한 문법

- 표현식이므로 값을 반환

- 패턴 매칭과 완벽하게 통합


switch 키워드는 "infix"입니다. 키워드는 테스트 된 값 (여기서는 o 임)과 표현식 lambdas와 같은 사례 목록 사이에 있음을 의미합니다. 다음 예제에서는 스위치 식과 잘 통합되지만 필수는 아닙니다.


static string Display(object o) => o switch

{

    Point { X: 0, Y: 0 }         => "origin",

    Point { X: var x, Y: var y } => $"({x}, {y})",

    _                            => "unknown"

};



Async streams


비동기 스트림은 C # 8의 또 다른 주요 개선점입니다. 

Visual Studio 2019 Preview 2 또는 Visual Studio Code의 C# extension에 대한 최신 버전에서 비동기 스트림을 사용하려면 .NET Core 3.0 Preview 2가 필요합니다. 명령 줄에서 .NET Core 3.0 Preview 2를 사용하면 모든 것이 예상대로 작동합니다.


IEEE Floating-point improvements


부동 소수점 API는 IEEE 754-2008 개정판을 준수하도록 업데이트되는 중입니다. 이 부동 소수점 프로젝트의 목표는 "필요한 모든"연산을 공개하고 해당 연산이 IEEE 스펙을 준수하는지 확인하는 것입니다.



.NET Platform Dependent Intrinsics


우리는 SIMD 또는 비트 조작 명령어 세트와 같은 특정 퍼센티지 지향 CPU 명령어에 액세스 할 수있는 API를 추가했습니다. 이러한 지침을 통해 데이터를 효율적으로 병렬 처리하는 등 특정 시나리오에서 성능을 크게 향상시킬 수 있습니다. 프로그램에 사용할 API를 공개하는 것 외에도 .NET 라이브러리를 가속화하기 위해이 지침을 사용하기 시작했습니다



.Introducing a fast in-box JSON Writer & JSON Document


System.Text.Json.Utf8JsonWriter 및 System.Text.Json.JsonDocument가 추가되었습니다.



GPIO Support for Raspberry Pi


Preview 2의 일부로 GPIO 프로그래밍에 사용할 수있는 두 개의 NuGet 패키지를 출시했습니다.


System.Device.Gpio


Iot.Device.Bindings



Local dotnet tools


로컬 닷넷 도구는 Preview 2에서 향상되었습니다. 로컬 도구는 dotnet 전역 도구와 유사하지만 디스크의 특정 위치와 연결됩니다. 이를 통해 프로젝트 및 저장소 별 관리가 가능합니다. .NET Core 3.0 Preview 1 게시물에서 자세한 내용을 볼 수 있습니다.



Assembly Unloadability


어셈블리 언로드 기능은 AssemblyLoaderContext의 새로운 기능입니다. 이 새로운 기능은 몇 가지 새로운 API로 공개 된 API 관점에서 크게 투명합니다. 이것은 인스턴스화 된 유형, 정적 필드 및 어셈블리 자체에 대한 모든 메모리를 해제하여 로더 컨텍스트를 언로드 할 수있게합니다. 응용 프로그램은 메모리 누수가 발생하지 않고이 메커니즘을 통해 어셈블리를로드 및 언로드 할 수 있어야합니다.



Windows Native Interop


Windows는 C API, COM 및 WinRT 형태로 풍부한 네이티브 API를 제공합니다. 우리는 .NET Core 1.0 이후 P/Invoke를 지원했으며, .NET Core 3.0 릴리스의 일부로 COM API를 CoCreate하고 WinRT API를 활성화하는 기능을 추가했습니다. 우리는 이러한 기능에 대한 많은 요청을 받았으며, 많이 사용하는 기능들을 앞으로도 추가할 예정입니다.



WPF and Windows Forms


WPF 및 Windows Forms 팀은 닷넷 코어 3.0 프리뷰 1이 발표 된 12월 4일에 dotnet/wpf 및 dotnet/winforms를 각각 오픈 소스로 전환 했습니다. 지난 달의 대부분은 휴일을 초월하여 커뮤니티와 상호 작용하고, 홍보를 병합하고, 문제에 응답하는 데 소비되었습니다. 백그라운드에서 WPF 및 Windows Forms를 Arcade SDK 채택을 포함하여 .NET Core 빌드 시스템에 통합했습니다. Arcade는 .NET Platform을 구축하는 데 필요한 기능을 제공하는 MSBuild SDK입니다. WPF 팀은 앞으로 몇 개월 동안 WPF 소스 코드를 더 많이 게시 할 예정입니다.



Visual Studio support


.NET Core 3의 데스크톱 개발에는 Visual Studio 2019가 필요합니다. 새 프로젝트 대화 상자에 WPF 및 Windows Forms 템플릿을 추가하여 명령 줄을 사용하지 않고도 새 응용 프로그램을보다 쉽게 시작할 수 있습니다.



MSIX Deployment for Desktop apps


MSIX는 새로운 Windows 응용 프로그램 패키지 형식입니다. .NET Core 3 데스크톱 응용 프로그램을 Windows 10에 배포하는 데 사용할 수 있습니다.


Visual Studio 2019 미리보기 2에서 사용할 수있는 Windows 응용 프로그램 패키징 프로젝트를 사용하면 자체 포함 된 .NET 핵심 응용 프로그램과 함께 MSIX 패키지를 만들 수 있습니다.



Install .NET Core 3.0 Previews on Linux with Snap


Snap은 Snap을 지원하는 Linux 배포판에서 .NET Core 미리보기를 설치하고 사용해 보는 것이 좋습니다. 현재 Snap을 사용하면 X64 빌드 만 지원됩니다. 우리는 ARM 빌드도 지원할 것입니다.



Platform Support


.NET Core 3 will be supported on the following operating systems:

  • Windows Client: 7, 8.1, 10 (1607+)
  • Windows Server: 2012 R2 SP1+
  • macOS: 10.12+
  • RHEL: 6+
  • Fedora: 26+
  • Ubuntu: 16.04+
  • Debian: 9+
  • SLES: 12+
  • openSUSE: 42.3+
  • Alpine: 3.8+

Chip support follows:

  • x64 on Windows, macOS, and Linux
  • x86 on Windows
  • ARM32 on Windows and Linux
  • ARM64 on Linux



Posted by MVP kaki104



UWP앱 개발을 시작하는 가장 좋은 방법은 Windows Template Studio로 시작하는 것입니다. 이번에 WTS 3.0 버전이 정식 릴리즈 되었습니다.


WTS 소스에 관심이 있으시면 WTS's GitHub를 방문하세요.



0. 참고 

Windows Template Studio 3.0 released!



1. 포함된 내용


- 새로운 프로젝트를 생성하면, 하나의 솔루션에 UWP 프로젝트와 .NET Core 프로젝트로 나누어서 생성됩니다.

- 마우스 오른쪽 버튼으로 새 프로젝트 추가 지원

- 수평 탐색보기가 피벗 탐색 패턴으로 변경됩니다.

- MVVMLight 패턴이 .NET Standard를 사용하도록 업데이트 되었습니다.

- 기타 버그 수정



2. 업데이트 방법


- 이미 설치되어 있는 경우 : Tools -> Extensions and Updates 로 이동합니다. 그런 다음 왼쪽의 Updates expander를 선택하시고 Windows Template Studio 를 선택 후 Update를 클릭하시면 됩니다.

- 미설시 : 



Online -> 검색창에 windows template studio -> download 버튼 클릭 -> Visual Studio 종료



3. 다음 추가 예정 내용


- 메뉴바 네비게이션 패턴 템플릿

- 로그인 아이덴티

- 향상된 Visual Studio 2019 서포트 

- Azure 기능들을 추가하기 시작

- Unit Test 프로젝트



4. 커뮤니티와의 파트너십을 통해 계속해서 새로운 기능을 추가 하고 있네요, 오픈 소스 프로젝트에 관심이 있는 분들의 많은 참여를 부탁드립니다. https://aka.ms/wts


기능 추가나 아이디어는 여기를 통해서 작성하시면 됩니다.





Posted by MVP kaki104




Project Rome은 디바이스를 뛰어 넘어 사용자 참여를 유도하는 경험을 창출하는 플랫폼으로, 개발자가 폼 팩터 나 플랫폼에 관계없이 사용자와 함께 이동하고 장치 중심이 아닌 인간 중심 시나리오를 만들 수 있도록 해주는 플랫폼입니다.


Windows 10 Anniversary Update에서 Remote Launch 및 Remote App Services를위한 Project Rome 기능을 처음 출시했습니다.




안드로이드 버전의 Project Rome SDK를 발표하게 된 것을 기쁘게 생각합니다. 이 SDK는 Java 및 Xamarin과 함께 작동합니다.


Project Rome SDK for Android 다운로드는 여기를 참고하세요


자세한 사항은 아래 블로그를 참고하세요

Project Rome blog posts


Posted by MVP kaki104

Windows 10 for ARM Install Lumia 950/XL


Windows 10 Pro for ARM64 version 1809를 Lumia 핸드폰에 설치하는 방법에 대한 상세한 안내입니다.


Windows10ForARM.pdf




YouTube 바로 가기

Posted by MVP kaki104
TAG arm, Lumia, windows


나만의 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


Posted by MVP kaki104

C1FlexGrid에 Custom MergeManager를 만들어서 사용하는 방법에 대한 예제가 모두 grid[r,c]에서 값을 가지고 와서 비교하도록 되어 있는데, 이 부분이 성능에 많은 영향을 줍니다. 


그래서, CollectionView에서 데이터를 직접 찾아서 비교하는 방법으로 성능을 50% 이상 올릴 수 있는 방법을 셈플로 만들어 보았습니다.


위의 성능 프로파일러만 보더라도 확연히 차이가 나는 것을 알 수 있습니다.


MainWindow.xaml


<Window x:Class="FlexGridMergeManagerSampleForWPF.MainWindow"
        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:local="clr-namespace:FlexGridMergeManagerSampleForWPF"
        xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Content="Using grid[r,c]" Click="ButtonBase_OnClick" />
            <Button Content="Using CollectionView" Click="ButtonBase_OnClick" />
        </StackPanel>
        <c1:C1FlexGrid x:Name="FlexGrid" Grid.Row="1"
                       HeadersVisibility="All"
                       AutoGenerateColumns="False"
                       AllowMerging="All"
                       GridLinesVisibility="All"
                       GridLinesBrush="LightGray"
                       FrozenLinesBrush="#FF2A4C80"
                       ColumnHeaderBackground="#FFDBE1E9"
                       RowHeaderBackground="#FFDBE1E9"
                       TopLeftCellBackground="#FFBAD2F5"
                       IsReadOnly="True"
                       AllowResizing="Both"
                       AllowSorting="True"
                       ShowMarquee="True"
                       ClipboardCopyMode="ExcludeHeader">
            <c1:C1FlexGrid.Columns>
                <c1:Column Binding="{Binding OrderID}" AllowMerging="False" />
                <c1:Column Binding="{Binding ProductID}" AllowMerging="True" />
                <c1:Column Binding="{Binding ProductName}" AllowMerging="True"/>
                <c1:Column Binding="{Binding UnitPrice}" AllowMerging="True" />
                <c1:Column Binding="{Binding Quantity}" AllowMerging="True" />
                <c1:Column Binding="{Binding Discount}" AllowMerging="True" />
                <c1:Column Binding="{Binding ExtendedPrice}" AllowMerging="True" />
            </c1:C1FlexGrid.Columns>
        </c1:C1FlexGrid>
    </Grid>
</Window>



MainWindow.xaml.cs


using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using C1.WPF.FlexGrid;

namespace FlexGridMergeManagerSampleForWPF
{
    /// <summary>
    ///     Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private const string CASE1 = "Using grid[r,c]";
        private const string CASE2 = "Using CollectionView";

        public MainWindow()
        {
            InitializeComponent();
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            var button = (Button) sender;
            switch (button.Content.ToString())
            {
                case CASE1:
                    BindGrid(CASE1);
                    break;
                case CASE2:
                    BindGrid(CASE2);
                    break;
            }
        }

        private void BindGrid(string type)
        {
            FlexGrid.MergeManager = new SampleMergeManager(type);

            var allText = File.ReadAllText("sample.csv");
            if (string.IsNullOrEmpty(allText)) return;
            var lines = allText.Split('\n');

            var items = (from line in lines.Skip(1)
                where string.IsNullOrEmpty(line) == false
                let columns = line.Split(',')
                select new SampleModel
                {
                    OrderID = Convert.ToInt32(columns[0]),
                    ProductID = Convert.ToInt32(columns[1]),
                    ProductName = columns[2],
                    UnitPrice = Convert.ToDouble(columns[3]),
                    Quantity = Convert.ToInt32(columns[4]),
                    Discount = Convert.ToDouble(columns[5]),
                    ExtendedPrice = Convert.ToDouble(columns[6].Replace("\r", ""))
                }).ToList();

            // bind grids to ListCollectionView
            FlexGrid.ItemsSource = items;
        }

        private class SampleMergeManager : IMergeManager
        {
            private static long _count;
            private readonly string _getDataType;

            public SampleMergeManager(string type)
            {
                _getDataType = type;
            }

            public CellRange GetMergedRange(C1FlexGrid grid, CellType cellType, CellRange rng)
            {
                if (cellType != CellType.Cell) return rng;
                var col = grid.Columns[rng.Column];
                if (col.AllowMerging == false) return rng;

                for (var i = rng.Row; i < grid.Rows.Count - 1; i++)
                {
                    if (CompareNext(grid, i, rng.Column))
                        break;
                    rng.Row2 = i + 1;
                }

                for (var i = rng.Row; i > 0; i--)
                {
                    if (ComparePrev(grid, i, rng.Column))
                        break;
                    rng.Row = i - 1;
                }

                _count++;
                Debug.WriteLine($"count : {_count}");
                return rng;
            }

            private bool CompareNext(C1FlexGrid grid, int r, int c)
            {
                if (_getDataType == CASE1)
                    return grid[r, c]?.ToString() != grid[r + 1, c]?.ToString();

                var col = grid.Columns[c];
                if (!(grid.CollectionView is ListCollectionView collection)) return false;
                var item1 = collection.GetItemAt(r);
                var item2 = collection.GetItemAt(r + 1);

                var property = item1.GetType().GetProperty(col.Binding.Path.Path);
                if (property == null) return false;
                var val1 = property.GetValue(item1);
                var val2 = property.GetValue(item2);

                return val1?.ToString() != val2?.ToString();
            }

            private bool ComparePrev(C1FlexGrid grid, int r, int c)
            {
                if (_getDataType == CASE1)
                    return grid[r, c]?.ToString() != grid[r - 1, c]?.ToString();

                var col = grid.Columns[c];
                if (!(grid.CollectionView is ListCollectionView collection)) return false;
                var item1 = collection.GetItemAt(r);
                var item2 = collection.GetItemAt(r - 1);

                var property = item1.GetType().GetProperty(col.Binding.Path.Path);
                if (property == null) return false;
                var val1 = property.GetValue(item1);
                var val2 = property.GetValue(item2);

                return val1?.ToString() != val2?.ToString();
            }

        }
    }
}


소스

https://github.com/kaki104/BasicSamples/tree/master/FlexGridMergeManagerSampleForWPF


'WPF' 카테고리의 다른 글

FlexGrid MergerManager 성능 개선 셈플 및 그래프  (0) 2018.12.20
GrapeCity WPF Edition (C1) tip  (0) 2018.12.19
.NetFrame 4.5 working tip  (0) 2013.06.12
Posted by MVP kaki104

GrapeCity WPF Edition (C1) tip

WPF / 2018.12.19 13:45


WPF 프로젝트를 하다보면, 기존에 WinForm에서 사용하던 형태의 그리드를 필요로 하는 경우가 많습니다.

특히 그리드에 머지 기능이 필요한 경우에는 Telerik RadGridView 보다 C1의 FlexGrid를 이용하는 것이 더 좋을 때도 있습니다.


FlexGrid를 이용해서 프로젝트를 할 때 버그나 Tip을 정리하도록 하겠습니다.

사용한 버전은 C1.WPF.FlexGrid version 4.0.20173.580입니다.



1. 무한 Custom MergeManager 호출


- FlexGrid에 AllowMerging이 활성화 되어 있고, MergeManager에 Custom MergeManager를 만들어서 연결한 경우

- ShowMarquee="True"로 설정하고

- 어플리케이션을 실행하고, FlexGrid를 클릭하면


Custom MergeManager를 무한 호출을 합니다. 이런 내용을 의도했다고 보기는 어려우니 버그이지 않을까 생각됩니다.

최신 버전에서는 이런 현상이 발생하지 않습니다.



2. WPF FlexGrid에 AllowMerging에 RestrictXXX 기능을 사용할 수 없습니다.


WinForm용 FlexGrid에는 RestrictAll, RestrictCols, RestrictRows 기능을 사용할 수 있어서, 머지를 할 때 왼쪽이나 위에 있는 데이터의 머지 상태에 따라서 머지를 해주는데, WPF용에는 해당 기능이 빠져있습니다. 그래서, Custom MergeManager를 이용해서 구현해야 하는 불편함이 있습니다.



3. Custom MergeManager 성능 향상


MergeManager를 만들어서 사용할려고, 검색을 해보면, 대부분의 자료는 아래 메소드를 호출해서 그리드의 데이터를 가지고 온 후에 비교를 하는 방식을 사용하라고 되어 있습니다.


    string GetDataDisplay(C1FlexGrid grid, int r, int c
   

       
return grid[r, c].ToString(); 
    } 


그런데, 여기서 문제는 grid[r, c].ToString() 컨트롤의 특정 셀을 찾고, 그 셀에서 값을 가지고 오는 과정에서 엄청난 성능 저하가 발생한다는 것입니다.


그래서, 컨트롤에 연결된 데이터에서 값을 찾아서 처리하는 방법을 만들었습니다.

        public class SampleMergeManager : IMergeManager
        {
            private static long Count;

            public CellRange GetMergedRange(C1FlexGrid grid, CellType cellType, CellRange rng)
            {
                if (cellType != CellType.Cell)
                    return rng;

                //if (rng.Column == 0)
                //    return rng;
                var vRange = grid.ViewRange;

                var itemsSource = grid.ItemsSource;

                for (int i = rng.Row; i < grid.Rows.Count - 1; i++)
                {
                    if (CompareNext(grid, i, rng.Column))
                        break;
                    rng.Row2 = i + 1;
                }

                for (int i = rng.Row; i > 0; i--)
                {
                    if (ComparePrev(grid, i, rng.Column))
                        break;
                    rng.Row = i - 1;
                }

                Count++;
                //Debug.WriteLine($"count : {Count} row1 : {rng.Row}, row2 : {rng.Row2}, col1 : {rng.Column}, col2 : {rng.Column2}");
                return rng;
            }

            private bool CompareNext(C1FlexGrid grid, int r, int c)
            {
                var col = grid.Columns[c];
                var collection = grid.CollectionView as ListCollectionView;

                var item1 = collection.GetItemAt(r);
                var item2 = collection.GetItemAt(r + 1);

                var property = item1.GetType().GetProperty(col.Binding.Path.Path);
                var val1 = property.GetValue(item1);
                var val2 = property.GetValue(item2);

                return val1?.ToString() != val2?.ToString();
            }

            private bool ComparePrev(C1FlexGrid grid, int r, int c)
            {
                //return grid[r, c]?.ToString() != grid[r - 1, c]?.ToString();
                var col = grid.Columns[c];
                var collection = grid.CollectionView as ListCollectionView;

                var item1 = collection.GetItemAt(r);
                var item2 = collection.GetItemAt(r - 1);
                var property = item1.GetType().GetProperty(col.Binding.Path.Path);
                var val1 = property.GetValue(item1);
                var val2 = property.GetValue(item2);

                return val1?.ToString() != val2?.ToString();
            }

        }


'WPF' 카테고리의 다른 글

FlexGrid MergerManager 성능 개선 셈플 및 그래프  (0) 2018.12.20
GrapeCity WPF Edition (C1) tip  (0) 2018.12.19
.NetFrame 4.5 working tip  (0) 2013.06.12
Posted by MVP kaki104


Amazon Polly를 이용해서 TTS를 만드는 간단한 셈플을 만들어 보도록 하겠습니다.


완성이되면 이런 화면에서 한글을 입력하고 폴리야~ 버튼을 클릭하면 설현(?) 목소리로 내용을 읽어 줍니다.



1. 준비


1) AWS를 이용하기 때문에 Amazon Web Service 계정이 필요합니다.

저도 없어서 새로 만들었습니다.


https://aws.amazon.com/ko/polly/


이 페이지를 상단에 무료 계정 생성하기 버튼을 클릭해서 계정을 만들면 됩니다.


2) 계정을 만들고 나면, IAM 관리자 및 계정을 만들어 주어야 합니다.


https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/getting-started_create-admin-group.html


이 페이지를 참고하셔서 IAM 계정을 생성하고, 그룹도 추가해 주시면 됩니다.


3) Polly 서비스를 사용하기 위해서 AccessKeyID와 SecretAccessKey가 필요합니다.


https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/id_credentials_access-keys.html


이 페이지를 참고하시면 만드실 수 있습니다.



2. 프로젝트 생성


Visual Stduio 2017를 실행하고, Windows Template Studio를 이용해서 단일 화면 프로젝트를 생성 했습니다.




3. NuGet Package 설치


AWSSDK.Core, AWSSDK.Polly 2개의 패키지를 선택해서 설치 합니다.



4. MainPage.xaml


            <StackPanel Grid.Row="1" Grid.Column="1">
                <TextBox Header="한글을 입력하세요" Text="{Binding InputText, Mode=TwoWay}"/>
                <Button Content="폴리야" Command="{Binding TTSCommand}"/>
                <MediaElement x:Name="MediaElement" RealTimePlayback="True">
                    <interactivity:Interaction.Behaviors>
                        <core:EventTriggerBehavior EventName="MediaEnded">
                            <core:InvokeCommandAction Command="{Binding MediaEndedCommand}"/>
                        </core:EventTriggerBehavior>
                        <behaviors:MediaBehavior Stream="{Binding RandomAccessStream, Mode=TwoWay}"/>
                    </interactivity:Interaction.Behaviors>
                </MediaElement>
            </StackPanel>



일반적인 코드입니다. 여기서 사용된 MediaBehavior는 지난번에 공유했던 내용이라 설명은 생략 합니다.


내부 코드는 좀 변경이 되었으니 맨 아래 공유해드리는 소스를 참고 하시면 될 것 같습니다.



5. MainViewModel.cs


        /// <summary>
        ///     TTS 커맨드 실행
        /// </summary>
        private async void ExecuteTTSCommand()
        {
            if (string.IsNullOrEmpty(InputText)) return;

            //폴리 클라이언트 생성
            var pc = new AmazonPollyClient("AccessKeyID를 입력하세요", "SecretAccessKey를 입력하세요"
                , RegionEndpoint.APNortheast2);

            //요청 생성
            var sreq = new SynthesizeSpeechRequest
            {
                Text = $"<speak>{InputText}</speak>",
                OutputFormat = OutputFormat.Mp3,
                VoiceId = VoiceId.Seoyeon,
                LanguageCode = "ko-KR",
                TextType = TextType.Ssml
            };

            InputText = string.Empty;

            //서비스 요청
            var sres = await pc.SynthesizeSpeechAsync(sreq);

            //서비스 요청 결과 확인
            if (sres.HttpStatusCode != HttpStatusCode.OK)
                return;

            //파일명 생성
            var fileName = $@"{ApplicationData.Current.LocalFolder.Path}\{DateTime.Now:yyMMddhhmmss}.mp3";
            //파일에 AudioStream 쓰기
            using (var fileStream = File.Create(fileName))
            {
                sres.AudioStream.CopyTo(fileStream);
                fileStream.Flush();
                fileStream.Close();
            }
            //생성된 파일을 가져오기
            var file = await StorageFile.GetFileFromPathAsync(fileName);
            //파일을 열어서 RandomAccessStream 프로퍼티에 입력
            RandomAccessStream = await file.OpenAsync(FileAccessMode.Read);

            //RandomAccessStream과 바인딩이 되어있는 MediaBehavior에서 MediaPlayer를 통해서 재생
        }


리즌 종류는 여기서 확인하세용

https://docs.aws.amazon.com/ko_kr/general/latest/gr/rande.html



6. 다운 받은 셈플 보이스



7. 소스


https://github.com/kaki104/AWSSamples



Posted by MVP kaki104
TAG aws, Polly

2018 청년에코 메이커 챌린지 행사에 멘토로 참석한 후기를 이제 올립니다.


행사 장소는 부산진구 호천마을이고 2018.8.10-8.11일까지 진행했습니다.


저는 금요일 저녁에 KTX를 타고 내려가서 토요일 하루 종일 참석을 했네요.


행사 장소가 호천 생활 문화 센터였는데, 처음 가본 부산 진구인지라..멋있는 곳이라고 생각했네요 


부산 시내 중고등학교 10개 팀이 참가해서 자연 친화 에너지를 이용한 건축물을 만드는 과정을 진행했습니다. 


오전 10시쯤 부터 시작했는데 몇시간 지나지 않아 건축물(?)이 만들어지는 모습이 신기하네요


오후 4시 반쯤 각 팀에서 만든 건축물에 대한 설명을 진행하고 있습니다.


하루종일 행사장에서 학생들과 함께 이야기하며, 만드는 과정을 지켜보았는데, 작품을 만드는 열정이 매우 높아서 놀랐습니다. 앞으로 이 학생들이 성인이 되어서도 환경을 생각하는 마음을 잊지 않고 더 열심히 정진하면 좋은 결과가 만들어 질 것 같습니다.


시간이 넉넉하지 않아서, S/W적인 부분에 대한 지원을 거의 하지 못했지만, 학생들의 작품 보강을 한다고 하면, 다시 참석해서 열심히 알려주고 싶습니다.


고생하신 환경단체 여러분들과 이런 좋은 행사를 알려주신 서인수 대표님께 감사드립니다.


Posted by MVP kaki104

티스토리 툴바