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

카테고리

List All (569)
Xamarin Forms (4)
Bot Framework (19)
Azure (9)
Windows 10 (44)
WPF (3)
Facebook News & Tips (158)
Windows App(Universa.. (90)
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)
Total530,056
Today0
Yesterday19


상세 페이지 구현 핵심 정리


* 상세 데이터 조회
* Layout Control - Grid, StackPanel, RelativePanel, Canvas
* TextBlock - HeaderedContentControl
* Image - ImageEx
* XAML design magic!!





소스


https://github.com/kaki104/PrismSample



Posted by MVP kaki104


Part 5

Prism으로 시작하는 UWP app Part5 - View에서 ViewModel로 사용자 인터렉션 연결하기

 

* SelectedItem

* SelectionChanged

* INavigationService

 

소스

https://github.com/kaki104/PrismSample





Posted by MVP kaki104

Part4


- View와 ViewModel 연결 방법
- ViewModel의 데이터를 View에 출력하기
- ItemsSource
- DataGrid


소스

https://github.com/kaki104/PrismSample




Posted by MVP kaki104


Part3 - 데이터 조회


- OMDb API 사용하기
- 화면 추가
- Json데이터로 Model 만들기
- JsonProperty 사용하기
- Add new feature, Settings Storage
- HttpClient로 데이터 조회하기




소스


https://github.com/kaki104/PrismSample


Posted by MVP kaki104


Part2 기본 화면 추가하기


- Windows Template Studio 다이얼로그를 이용해서 화면 추가
- TextBlock과 Button을 추가
- MVVM 패턴의 맛보기 Binding 약간, Command 약간



소스


https://github.com/kaki104/PrismSample


* 질문이나 다루었으면 하는 내용들은 유투브에 리플로 남겨주시면.. 최대한 알아보고 아는 만큼만 설명드리도록 하겠습니다.





Posted by MVP kaki104


2019년 UWP앱 개발을 시작할 때가 되었습니다.


기본적인 내용을 공부하고 접근하면 너우 오래 걸릴 수 있습니다. 그래서, 일단 만들고 각자 이론 공부하시는 것으로 방향을 잡았습니다.


일주일에 한편씩은 업로드 하도록 노력하겠습니다. 그리고, 질문이나 다루었으면 하는 내용들은 유투브에 리플로 남겨주시면.. 최대한 알아보고 아는 만큼만 설명드리도록 하겠습니다.


감사합니다.


part100번까지 가보도록 하죠;;




소스


https://github.com/kaki104/PrismSample


Posted by MVP kaki104
TAG #prism, #uwp

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

페이스북 그룹에 올려주신 문의 내용에 맞는 셈플을 만들어 보았습니다.
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

UWP앱들을 보면 검색 버튼을 클릭하면 택스트 박스가 출력되는 UI를 자주 볼 수 있습니다.


음..기본으로 제공되는 줄 알았는데..그러지는 않더군요..ㅋㅋ

간단하게 만들어보았습니다.


1. XAML


<Page>

    <Page.Resources>

        <Style x:Key="SearchBoxStyle" TargetType="FlyoutPresenter">
            <Setter Property="Margin" Value="78,0,0,0"/>
            <Setter Property="Padding" Value="5"/>
            <Setter Property="Height" Value="50"/>
        </Style>

    </Page.Resources>

    <Grid>


        <CommandBar Background="Transparent" IsOpen="False" DefaultLabelPosition="Right">
            <AppBarButton Icon="Find" Label="Find">
                <AppBarButton.Flyout>
                    <Flyout Placement="Left" FlyoutPresenterStyle="{StaticResource SearchBoxStyle}"
                            Opened="FlyoutBase_OnOpened">
                        <AutoSuggestBox x:Name="SuggestBox" PlaceholderText="Input words to search" AllowFocusOnInteraction="True" />
                    </Flyout>
                </AppBarButton.Flyout>
            </AppBarButton>

            <AppBarButton Icon="Add" Label="Add" Command="{Binding AddCommand}"/>
        </CommandBar>

    </Grid>

</Page>



2. XAML.CS


        private void FlyoutBase_OnOpened(object sender, object e)
        {
            SuggestBox.Focus(FocusState.Programmatic);
        }



3. 설명


여기서 핵심은 AppBarButton의 Flyout을 이용해서 툴팁 같은 팝업을 출력하는 것입니다. 그 내부에 메뉴도 넣을 수 있고, 머 여러가지로 활용을 하는데.. 이번에는 AutoSuggestBox를 집어 넣은 것입니다.


AutoSuggestBox가 Windows 10의 기본 검색 컨트롤이라고 하네요..음..SearchBox 컨트롤도 존재하지만, 이전 버전에서 사용되는 컨트롤이라...


검색 버튼을 누르기전




검색 버튼을 누른 후


검색 버튼을 누른 후 포커스를 넣기 위해서 CS에서 코딩을 하나 했습니다.

CS 코딩이 싫은 분들은 Behavior를 만들어서 사용하시면 됩니다.


Posted by MVP kaki104



NAS에 MariaDB(MySQL)를 설치는 했는데..어떻게 사용해야 할까요? (약 1시간 정도 고민..) 

역시 가장 만만한 RESTfull 서비스를 만들어서 호출하면 되겠죠? 그렇다면, Azure에서 RESTfull 서비스를 만들어서 CRUD를 해 볼까요?


MySQL과 연결하는 서비스를 만드는 것이 저도 처음이라 엄청난 삽질을 했습니다. ㅋㅋ 간단하지는 않네요.



0. 참고

NAS에 Database를?

NorthWind Database 생성

Visual Studio를 사용하여 Azure App Service에서 웹앱 문제 해결

ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'db'

Connect C# to MySQL



1. MySQL에 NorthWind Database 생성


참고에 있는 NorthWind Database 생성 페이지에서 Northwind.MySQL5.sql을 다운로드 합니다.


SQLyog 프로그램을 실행해서 DB에 접속하고, 다운로드받은 쿼리를 불러온 후 실행하면, northwind db가 생성됩니다.




2. 셈플 프로젝트 생성


Visual Studio를 실행하고 New -> Project를 선택하고 다음과 같이 선택합니다.



ASP.NET Web Application을 선택합니다. 여기서 해당 내용들이 나오지 않는다면, 비주얼 스튜디오를 설치할 때 웹 관련 항목을 선택하지 않았기 때문입니다. 그리고, Azure와 관련된 최신 업데이트를 완료하세요.


OK를 입력하여 다음 화면으로 넘어 갑니다.



여기서 Azure API App을 선택하고, OK를 클릭합니다.


프로젝트 생성 완료!



3. MySQL 사용을 위한 준비


프로젝트에서 오른쪽 버튼을 눌러 NuGet packages를 선택합니다.


Browse 탭에서 MySQL을 검색해서 MySQL.Data를 선택하고 설치합니다.




4. MySQLHelper


DB에 접속해서 쿼리를 실행시키는 부분을 헬퍼 클래스로 분리 합니다.


    /// <summary>
    ///     MySQL 헬퍼 클래스
    /// </summary>
    public class MySQLHelper
    {
        private static MySQLHelper _instance;

        private MySqlConnection _connection;

        /// <summary>
        ///     생성자
        /// </summary>
        public MySQLHelper()
        {
            Initialize();
        }

        /// <summary>
        ///     인스턴스
        /// </summary>
        public static MySQLHelper Instance => _instance ?? (_instance = new MySQLHelper());

        /// <summary>
        ///     초기화
        /// </summary>
        private void Initialize()
        {
            var server = "NAS 외부접속 아이피";
            var database = "northwind";
            var uid = "kakiadmin";
            var password = "비밀번호";
            var connectionString =
                $"SERVER={server};DATABASE={database};UID={uid};Pwd={password};SslMode=none;";

            _connection = new MySqlConnection(connectionString);
        }

        /// <summary>
        ///     연결
        /// </summary>
        /// <returns></returns>
        private Tuple<bool, string> OpenConnection()
        {
            try
            {
                _connection.Open();
                return new Tuple<bool, string>(true, null);
            }
            catch (MySqlException ex)
            {
                //When handling errors, you can your application's response based
                //on the error number.
                //The two most common error numbers when connecting are as follows:
                //0: Cannot connect to server.
                //1045: Invalid user name and/or password.
                switch (ex.Number)
                {
                    case 0:
                        Debug.WriteLine("Cannot connect to server.  Contact administrator");
                        break;

                    case 1045:
                        Debug.WriteLine("Invalid username/password, please try again");
                        break;
                }

                return new Tuple<bool, string>(false, ex.Message);
            }
        }

        /// <summary>
        ///     연결 종료
        /// </summary>
        /// <returns></returns>
        private bool CloseConnection()
        {
            try
            {
                _connection.Close();
                return true;
            }
            catch (MySqlException ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }

        /// <summary>
        ///     연결 테스트
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetConnectTestAsync()
        {
            var ds = new DataSet();
            var query = "SELECT * FROM Employees";
            var result = OpenConnection();
            if (result.Item1 == false) return result.Item2;
            var adpt = new MySqlDataAdapter(query, _connection);
            //var cmd = new MySqlCommand(query, _connection);
            await adpt.FillAsync(ds);
            CloseConnection();
            return "success connecting";
        }

        /// <summary>
        ///     결과 반환하지 않는 쿼리 실행, Insert, Update, Delete
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<string> ExecuteNonQueryAsync(string query)
        {
            if (string.IsNullOrEmpty(query)) return "Empty strings are not supported.";
            var result = OpenConnection();
            if (result.Item1 == false) return result.Item2;
            var cmd = new MySqlCommand(query, _connection);
            var resultExecute = await cmd.ExecuteNonQueryAsync();
            CloseConnection();
            return resultExecute.ToString();
        }

        /// <summary>
        ///     결과 반환하는 쿼리 실행 Select
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<DataSet> ExecuteAsync(string query)
        {
            if (string.IsNullOrEmpty(query)) return null;
            var ds = new DataSet();
            var result = OpenConnection();
            if (result.Item1 == false) return null;
            var adpt = new MySqlDataAdapter(query, _connection);
            await adpt.FillAsync(ds);
            CloseConnection();
            return ds;
        }
    }


Initialize()에 접속 아이디와 비밀번호는 지난번 포스트에서 이야기 했듯이 telnet으로 연결해서 직접 추가를 해주어야 합니다.


mysql에 root 아이디로 접속


$ mysql -uroot -p


kakiadmin 아이디 추가


mysql> CREATE USER 'kakiadmin'@'192.168.35.1' IDENTIFIED BY 'your_password';
mysql
> grant all privileges on *.* to 'kakiadmin'@'192.168.35.1';


여기서 주의할 사항은 아이디를 추가할 때 뒤에 붙이는 아이피는 집에서 테스트를 할 때는 게이트웨이 주소를 넣으셔야 하며, 차후 Azure에 서비스를 올리면 Azure 서비스에서 사용하는 아이피를 넣어야 한다는 것입니다. 


동일한 이름을 가지고 있어서 호출하는 Ip에 맞춰서 아이디가 각각 존재해야 한다는 점입니다.


어떤 아이피를 가지는 아이디를 추가해야하는지 확인하기 위해서 GetConnectTest 메소드를 호출하면 됩니다.



5. ValuesController.cs 수정


        /// <summary>
        ///     연결 테스트
        /// </summary>
        /// <returns></returns>
        [Route("~/getconnecttest")]
        public async Task<string> GetConnectTest()
        {
            return await MySQLHelper.Instance.GetConnectTestAsync();
        }


위의 코드를 추가한 후 실행하면 브라우저에서는 HTTP Error 403.14 - Forbidden 이런 오류가 출력되는데 무시하고, localhost:12267을 복사한 후 postman을 이용해서 테스트를 해봅니다.


정상적으로 연결이 완료되고, 데이터를 조회했다면 다음과 같은 결과가 반환됩니다.

실패했을 경우 1045 오류가 발생하면서, 메시지가 나오는데 그 곳에 나오는 아이피를 이용해서 아이디를 추가해주시면 됩니다.


여기서 제가 실패하지 않는 이유는 이미 로컬 아이피를 이용해서 계정을 등록해 놓았기 때문입니다. 처음하시는 분들은 여기서 반드시 오류가 발생합니다. 9번 항목을 참고해서 처리하세요



6. 데이터 조회


        // GET api/values
        [SwaggerOperation("GetAll")]
        public async Task<DataSet> Get()
        {
            return await MySQLHelper.Instance.ExecuteAsync("SELECT * FROM Products");
        }


ValuesController.cs에 Get메소드를 위와 같이 수정하고 실행 합니다.


postman에서 http://localhost:12267/api/values를 호출하면 결과가 반환 됩니다.


DataSet을 Json형태로 변환해서 반환합니다.

물론 여기서는 쿼리를 미리 입력해서 처리했지만, request로 받아서 처리할수도 있겠죠? 쿼리를 직접 받기 위해서는 Post를 이용해야 합니다.



7. 쿼리 직접 입력 받아서 실행하기


        // POST api/values
        [SwaggerOperation("Create")]
        [SwaggerResponse(HttpStatusCode.Created)]
        public async void Post([FromBody]JObject value)
        {
            var query = value["value"].ToString();
            var result = await MySQLHelper.Instance.ExecuteNonQueryAsync(query);
        }


ValueController.cs를 위와 같이 수정합니다. 특히 string을 JObject로 수정하는 것을 잊으면 않됩니다.


수정 완료 후 postman에서 아래와 같이 호출합니다.


post를 선택하고, http://localhost:12267/api/values를 입력합니다.

headers에 content-type은 x-www-form-urlencoded로 지정되어 있어야 하며, Body에 x-www-form-urlencoded를 선택한 후 value, INSERT Employees(LastName, FirstName) VALUES('Park','MunChan'); 를 각각 입력 후 send를 누릅니다.


물론 반환되는 결과는 없습니다. 호출후 db를 조회해보면 Employees 테이블에 레코드가 하나 추가되어있는 것을 볼 수 있습니다.



8. 서비스를 Azure에 올리기


프로젝트에서 마우스 오른쪽 -> Publish를 선택하면 아래와 같은 화면이 나옵니다. Create New에서 Publish를 눌러줍니다.



Create App Service에서 App 이름을 지정하고, 서브스크립션을 선택합니다. 비주얼 스튜디오 로그인된 계정으로 가입된 Azure 계정을 찾는것이 기본이며, 다른 계정을 선택하실 수도 있습니다. 


MVP는 MSDN 서브스크립션을 가지고 있기 때문에 선택했습니다. 그외 Resource Group, Hosting Plan등은 사용자가 임으로 만들어서 사용하시면 됩니다.


Create 버튼을 눌러서 서비스를 생성하면 됩니다.



배포가 완료되면 



완료화면이 출력됩니다. 이제 서비스를 호출해서 테스트 합니다.



9. 마무리 작업


postman으로 http://mysqlsample2018.azurewebsites.net/getconnecttest 주소를 get 호출하면


"Authentication to host 'xx.xx.xx.xx' for user 'kakiadmin' using method 'mysql_native_password' failed with message: Access denied for user 'kakiadmin'@'52.231.xx.xxx' (using password: YES)"


위와 같은 오류가 발생합니다. 즉, kakiadmin으로 MySQL 에 로그인을 하지 못했다는 내용입니다. 그런데 찾는 계정이 'kakiadmin'@'52.231.xx.xxx' 입니다. 이런 경우 해당 계정을 MySQL 에 추가해 주어야만 로그인이 가능합니다.


추가!!

뒤에 ip부분을 생략하고 싶으면 kakiadmin@% 이렇게 만들면 어떤 아이피든지 통과가 가능합니다. ㅜㅜ



4번에 있는 방법을 이용해서 계정을 추가해 주면 완료 가능합니다.


아이디를 추가한 후 다시 호출해보니 success connecting이라는 메시지가 출력되었습니다.


마지막으로 조회를 테스트해보니 정상적으로 조회되는 것을 알 수 있습니다.

최종 소스에서 조회하는 테이블을 Employees로 변경했습니다.


http://mysqlsample2018.azurewebsites.net/api/values


{
    "Table": [
        {
            "ProductID": 1,
            "ProductName": "Chai",
            "SupplierID": 1,
            "CategoryID": 1,
            "QuantityPerUnit": "10 boxes x 20 bags",
            "UnitPrice": 18,
            "UnitsInStock": 39,
            "UnitsOnOrder": 0,
            "ReorderLevel": 10,
            "Discontinued": 0
        },
        {
            "ProductID": 2,
            "ProductName": "Chang",
            "SupplierID": 1,
            "CategoryID": 1,
            "QuantityPerUnit": "24 - 12 oz bottles",
            "UnitPrice": 19,
            "UnitsInStock": 17,
            "UnitsOnOrder": 40,
            "ReorderLevel": 25,
            "Discontinued": 0
        },

.....



10. Azure debug


에저에 올라간 서비스의 에러를 확인하기 위해서는 참고에 있는 내용을 참고하시면 될 것 같습니다.



11. 소스

https://github.com/kaki104/ConnectingAzureToMySQL


Posted by MVP kaki104