개발팁2016. 7. 26. 09:46

C# 어플리케이션, 보통 winform 형태의 어플리케이션에서
캐쉬를 만들고 처리하는 방법이다.

 

캐쉬는 데이터를 저장하고 꺼내쓰기 위해서 사용을 하는데,
데이터를 읽기 위해서 매번, 저장소에서 꺼내오는 것이 아니라,
저장소에서 읽어서 캐쉬에 저장을 해놓고, 캐쉬에서 꺼내쓴다면,
속도 향상과, 저장소에 대한 트래픽을 줄일수 있어 효율적으로 사용이 가능하다.

 

아래와 같은 방법으로 저장소에 대해서 자료를 가져오는 클래스를 정의하여 사용하면,
데이터를 가져다 쓰는 객체는 내부 구조에 상관없이 동일한 인터페이스로 사용할 수 있을것이다.


자료 클래스


- 자료읽기 요청
  1. 캐쉬에서 자료 읽기
     데이터가 없으면, 저장소에서 읽어옴
     캐쉬에 자료 저장
  2. 읽어온 자료 리턴

 

- 자료쓰기 요청
  1. 저장소에 자료 쓰기
  2. 캐쉬 삭제

 


저장소는 외부에서 변경되지 않는다는 보장이 되어야 한다.
외부에서 변경된다면, 캐쉬데이터와 저장소데이터간에 차이가 발생하게 된다.

실제로 Application Cache Object 를 아래와 같이 구현하였다.


 

    // Application 캐쉬 객체
    class AppCacheObject
    {
        private static HttpRuntime _httpRuntime;

        public static Cache Cache
        {
            get
            {
                EnsureHttpRuntime();
                return HttpRuntime.Cache;
            }
        }

        private static void EnsureHttpRuntime()
        {
            if (null == _httpRuntime)
            {
                try
                {
                    Monitor.Enter(typeof(AppCacheObject));
                    if (null == _httpRuntime)
                    {
                        _httpRuntime = new HttpRuntime();
                    }
                }
                finally
                {
                    Monitor.Exit(typeof(AppCacheObject));
                }
            }
        }

    } 

 

Cache 는 System.Web.Caching.Cache 의 객체이며, Get Property 로 사용한다.
System.Web 을 사용하기 때문에, System.Web.HttpRuntime 의 Cache 객체로 생성한다.

 

이는 Cache 객체에 대한 정의이며, 이를 이용하여,
캐쉬를 저장하는 SetCache
캐쉬를 조회하는 GetCache
캐쉬를 삭제하는 RemoveCache

 

여기서 한가지 중요한 것이, 캐쉬종류이다.
Absolute Expiration 과 Sliding Expiration 이라는것이 있다.

 

Absolute Expiration 은 지정된 만료시간이 지나면, 무조건 캐쉬가 삭제되는 것이고,
Sliding Expiration 은 동일하게 지정된 만료시간에 캐쉬가 삭제되지만, GetCache 를 할때마다 자동으로 만료시간이 연장이 된다.

 

일반적으로 로그인 처리를 하여, 로그인정보를 저장할때 Sliding Expiration Cache 를 사용하면,
지정된 시간이 지나면, 자동로그아웃이 되지만, 계속 작업을 한다면 (작업시마다 캐쉬를 사용하여 로그인정보를 확인) 로그인이 풀리지 않게 되는것이다.

 

실제로, AppCacheManager 라는 클래스로,
SetCache / GetCache / RemoveCache 와 슬라이딩 캐쉬를 구현한 것이다.
슬라딩캐쉬는 SetCache 에서만 지정해주면, GetCache / RemoveCache 는 동일하게 사용된다.

 

    // Copyright 헝그리개발자(https://bemeal2.tistory.com)
    // 소스는 자유롭게 사용가능합니다. Copyright 는 삭제하지 마세요.

    // Application 캐쉬
    public class AppCacheManager
    {
        // 인증용 캐쉬 저장 : 슬라이딩 만료 캐쉬 - minute 후에 만료되지만, GetCache 요청이 있으면, 만료시간이 연장됨
        public static bool SetSlidingCache(string name, object value, int minute)
        {
            bool bvalue = true;

            try
            {
                AppCacheObject.Cache.Add(name, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(minute), CacheItemPriority.Normal, null);
            }
            catch
            {
                bvalue = false;
            }

            return bvalue;
        }

        // 캐쉬 저장 : 절대 시간 만료 캐쉬 - minute 후에 만료
        public static bool SetCache(string name, object value, int minute)
        {
            bool bvalue = true;

            try
            {
                AppCacheObject.Cache.Add(name, value, null, DateTime.Now.AddMinutes(minute), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
            }
            catch
            {
                bvalue = false;
            }

            return bvalue;
        }

        // 캐쉬 get
        public static Object GetCache(string name)
        {
            Object ovalue = new Object();

            try
            {
                ovalue = AppCacheObject.Cache.Get(name);
            }
            catch { }

            return ovalue;
        }

        // 캐쉬 제거
        public static Object RemoveCache(string name)
        {
            Object ovalue = new Object();

            try
            {
                ovalue = AppCacheObject.Cache.Remove(name);
            }
            catch { }

            return ovalue;
        }

    } 

 

 

 

 

이를 이용하여, AppCacheExample 을 실행해보면,
로그인정보를 저장하는 Sliding Cache 와 일반 정보를 저장하는 Absolute Cache 를 사용하고 있다.
각각 캐쉬 만료시간을 1분으로 하여,
GetCache 를 했을때, 만료되는지와 자동연장되는지를 확인할 수 있다.

 

 

 

 

AppCacheExample.zip
다운로드

 

Posted by 헝개
개발팁2016. 7. 23. 09:15

윈도우7에서 JDK 8 을 설치할때, 아래와 같은 오류가 나면서 설치가 안될때,
해결 방법입니다.

 

 

 

오류 내용은 sj180920.cab 파일이 잘못되었다는 내용인데,
일단 이러한 오류가 났을때는,

 


JRE 8 을 수동 다운로드 하여, 설치하고, JDK 8 을 설치하면 해결이 된다.

 

JRE 는 Java Runtime 환경으로, Java 를 실행하기 위한 환경이고,
JDK 는 Java Development 환경이다. 따라서 JDK 에는 JRE 가 포함이 되어 있다.

 

JRE 8 수동 다운로드 URL 이다.

https://java.com/en/download/manual.jsp

 

Posted by 헝개
개발팁2016. 7. 22. 00:30

주민번호는 AAAAAA-XBBBBBY
- 를 빼면 숫자 13자리이다.

 

앞에 6자리는 생년월일이고,
뒤에 7자리중에 첫번째가 구분값이다.


이값이 5,6,7,8 이면, 재외국인이며, 그외에는 내국인이다.


맨뒤 1자리는 오류검증값이 된다.

 

유효성 검증로직은

13번째 오류검증값을 제외하고, 12개의 숫자를


234567892345
이 숫자와 각 자리수별로 곱한다음 sum 을 한다.


이 값을 11로 나눈 나머지를 11에서 빼고, 맨뒤 1의 자리(0~9)만 취한다.
이 값에 다시 2를 더한다음, 맨뒤 1의 자리(0~9)만 취한다.
이 값이 오류검증값이 되는 것이다.

 

// Copyright 헝그리개발자​(http://bemeal2.tistory.com)
// 소스는 자유롭게 사용가능합니다. Copyright 는 삭제하지 마세요.

// 재외국인 주민번호 유효성 검사
private static bool IsValidForeignRegNo(string reg_no)
{
    int sum = 0;
    int odd = 0;

    int[] arrBuffer = new int[13];


    for(int i=0; i < 13; i++)
    {
         arrBuffer[i] = Convert.ToInt32(reg_no[i].ToString());
    }



    odd = arrBuffer[7]*10 + arrBuffer[8];


    if(odd % 2 != 0)
         return false;



    int[] multipliers = {2,3,4,5,6,7,8,9,2,3,4,5};


    for(int i=0; i < 12; i++)
    {
         sum += (arrBuffer[i] *= multipliers[i]);
    }


    sum = 11 - (sum % 11);



    if(sum >= 10)
         sum -= 10;



    sum += 2;


    if(sum >= 10)
         sum -= 10;



    return (sum == arrBuffer[12]);


}

 

코드는 C# 으로 작성되었으나, 코드가 아주 간단하여, 사용하는 언어로 포팅하여 사용하면 된다.

 

Posted by 헝개
개발팁2016. 7. 21. 09:54

사업자 등록번호는 AAA-BB-CCCCY 의 구조이며,
- 를 제외하면, 숫자로 10자리이다.

 

앞의 세자리는 국세청과 세무서별 코드
가운데 두자리는 개인과 법인
뒤에 5자리수중에 앞쪽 4자리는 일련번호
맨 끝자리 1개는 오류검증값이다.

 

유효성 검증로직은

오류검증값을 제외한 9자리를


137137135
이 숫자와 각 자리수별로 곱하여 sum 을 한다.


여기에, 9번째 자리 * 5 / 10 을 한 값을 더하고,
맨뒤 1의 자리 숫자(0~9)만을 취하여,
10 - 맨 마지막값 을 한것이 오류검증값이 되는 것이다.


 

// Copyright 헝그리개발자​(http://bemeal2.tistory.com)
// 소스는 자유롭게 사용가능합니다. Copyright 는 삭제하지 마세요.

// 사업자등록번호 유효성 검사
public static bool IsValidBizNo(string biz_no)
{
    biz_no = biz_no.Replace(" ", ""); //공백 제거
    biz_no = biz_no.Replace("-", ""); // 문자 '-' 제거



    if (biz_no.Length != 10) //사업자 등록번호가 10자리인가?
    {
         return false;
    }



    int sum = 0;
    int checknum = 0;
    int[] arrNumList = new int[10];
    int[] arrCheckNum = {1,3,7,1,3,7,1,3,5};



    for (int i = 0; i < 10; i++)
    {
         arrNumList[i] = Convert.ToInt32(biz_no[i].ToString());
    }



    for (int i = 0; i < 9; i++)
    {
         sum += arrNumList[i] * arrCheckNum[i];
    }



    sum += ((arrNumList[8] * 5) / 10);
    checknum = (10 - sum % 10) % 10;



    return (checknum == arrNumList[9]);

 

코드는 C# 으로 작성되었으나, 코드가 아주 간단하여, 사용하는 언어로 포팅하여 사용하면 된다.

 

Posted by 헝개
개발팁2016. 7. 20. 09:41

ASP.NET 의 View 를 ViewEngine 으로 렌더링해서 나온 HTML 을 엑셀로 내려받는 방법이다.

 

아래와 같이 2개의 정적 메서드를 정적 클래스 (static class) 안에 정의한다.

 

// Copyright 헝그리개발자​(http://bemeal2.tistory.com)
// 소스는 자유롭게 사용가능합니다. Copyright 는 삭제하지 마세요.

// HTML 을 엑셀파일로 웹 다운로드
public static void ToExcelDownload(this string strHTML, string filename)
{
    filename = filename.Replace(" ", "_");



    HttpContext.Current.Response.AppendHeader("content-disposition", "attachment;filename=" + HttpUtility.UrlEncode(filename));
    HttpContext.Current.Response.Charset = "";
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
    HttpContext.Current.Response.Write(strHTML);
    HttpContext.Current.Response.End();
}



// View 를 HTML 문자열로 변환
public static string ViewToString(this ControllerContext controller, string viewName, ViewDataDictionary ViewData, TempDataDictionary TempData, object model)
{
    ViewData.Model = model;
    using (var sw = new StringWriter())
    {
         var viewResult = ViewEngines.Engines.FindPartialView(controller, viewName);
         var viewContext = new ViewContext(controller, viewResult.View, ViewData, TempData, sw);
         viewResult.View.Render(viewContext, sw);
         viewResult.ViewEngine.ReleaseView(controller, viewResult.View);


         return sw.GetStringBuilder().ToString();
    }
}

 

ToExcelDownload 메서드는 문자열(html)을 엑셀타입으로 내려받도록 해준다.

실제 내용은 table 테그로 구성된 html 이지만, 엑셀 형식으로 다운로드하도록 해주는 것이다.

 

ViewToString 메서드는 ViewContext 로, View 를 렌더링해서 String 으로 만들어준다.

 

 

엑셀 다운로드 버튼에 대한 Controller 를 아래와 같이 정의할 수 있다.

Model 을 구성하여, ViewToString 으로 View 이름과 Model 객체를 전달하여 준다.

예제에서는 Controller 이름과 동일한 이름의 View 이름을 사용하였다.

 

이 말은, 현재 Controller 의 View 를 호출하여 렌더링 한다는 뜻이다.

물론, 다른 Controller 의 View 이름을 넣어주어도 상관이 없다. 해당 View 에 맞는 Model 만 생성해서 전달해주면 된다.

 

 // 엑셀 다운로드에 대한 컨트롤러
public ActionResult Sample_ExcelDownload(int key_id)
{
    MySampleDataContainer model = new MySampleDataContainer();



    BizSample biz = new BizSample();
    model.header = biz.SampleDataInfo(key_id);
    model.list = biz.SampleDataList(key_id);



    string strHTML = this.ControllerContext.ViewToString("Sample_ExcelDownload", this.ViewData, this.TempData, model);
    string filename = "excel_download_sample.xls";
    strHTML.ToExcelDownload(filename);

    return View();
}

 

 

View 내용인데, 일반적으로 사용하는 View 와 동일하다.

다만 Excel 파일로 열어줘야 하기 때문에 엑셀에서 인식하도록 몇가지 태그가 추가되었을 뿐이다.

 

 // 엑셀 내용에 대한 뷰 - Sample_ExcelDownload
@model HD.DataFactory.MySampleDataContainer
@{
    ViewBag.Title = "Excel";
    Layout = "~/Views/Shared/_ContentLayout.cshtml";
}

<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
<head>
    <meta content="text/html; charset=utf-8" http-equiv="content-type" />
    <!--[if gte mso 9]>
<xml>
<x:ExcelWorkbook>
<x:ExcelWorksheets>
<x:ExcelWorksheet>
<x:Name>sheet name</x:Name>
<x:WorksheetOptions>
<x:DisplayGridlines/>
</x:WorksheetOptions>
</x:ExcelWorksheet>
</x:ExcelWorksheets>
</x:ExcelWorkbook>
</xml>
<![endif]-->
</head>
<body>

<table class="doc_data_list" border="1">
...
</table>

</body>
</html>

 

 

Posted by 헝개
개발팁2016. 7. 19. 11:14

Extention Method C# 3.0 에서 추가된 기능이다.

 

Extention Method 를 정의하는 방법은

 

1. System.Linq 를 사용하겠다고 선언한다.
2. static 클래스와 static 메서드로 정의해야 한다.
3. 첫번째 파라미터에 this 라는 키워드를 사용한다.


 

using System.Linq;

namespace test
{
 public static class Extention
 {
  public static string ToUpperCase(this string value)
  {
   // to do...

   return outString;
  }
  public static string AddString(this string value, string extraValue)
  {
   // to do...

   return outString;
  }
 }
}

 

사용방법

 

string str1 = "abcd efgh";
string str2 = "001002003";

 

// 기존 메서드 호출방법
string outStr1 = Extention.ToUpperCase(str1);
string outStr2 = Extention.AddString(str1, str2);

 

// 확장 메서드 호출방법
string extStr1 = str1.ToUpperCase();
string extStr2 = str1.AddString(str2);

 

 

기존 메서드 호출방법과 확장 메서드 호출방법을 모두 다 사용 가능하다.

 

 

 

 

확장메서드는 Visual Studio 에서 보면, 멤버 메서드와 동일하게 보여지고, 사용된다.

다른점은 오른쪽에 (확장) 이라고 표시가 된다.

 

 

 

배열에서의 확장메서드

 

// 정의

public static int[] OrderByAscending(this int[] n)
{
    // to do...
    return outN;
}

 

// 사용시

int[] nList = { 6, 7, 2, 7, 4, 9, 10, 11, 1 };
nList.OrderByAscending();
 

 

 

IEnumerable Generic 에도 이용할 수 있다.

 

// 정의

public static IEnumerable<T> GetOddData<T>(this IEnumerable<T> data)
{
    int n = 1;
    foreach (T Element in data)
    {
 if ((n++ % 2) == 0)
     yield return Element;
    }
}

 

// 사용

List<int> nList = new List<int>() { 1,2,3,4,5,6,7,8,9,10 };
Dictionary<int, string> Dic = new Dictionary<int, string>() { { 1, "one" }, { 2, "two" }, { 3, "three" }, { 4, "four" }, { 5, "five" }, { 6, "six" } };

 

foreach (int val in nList.GetOddData())
{
 Console.WriteLine(val);
}

 

foreach (var kvValue in Dic.GetOddData())
{
 Console.WriteLine(kvValue.Key + " " + kvValue.Value);
}

 

 

이와같이 홀수번째 데이터만 모아서
IEnumerable 로 리턴하는 Extention Method 를 정의하고,


IEnumerable 에서 상속받은 List 와 Dictionary 객체에
GetOddData 메서드를 그대로 사용하는 방법이다.

Posted by 헝개
개발팁2016. 7. 17. 13:48

만나이는 년도로 나이를 계산후에, 생일이 안지났으면 1을 빼주면되는, 간단한 공식이다.

 

테이블 컬럼에 생년월일 컬럼이 있다면, 더 심플하게 구현이 가능하고,
음력생일 이라면, 양력생일로 변환후에 위의 로직으로 하면된다.


음력을 양력으로 변환하는 것은, DB에서 처리할때는 음/양 맵핑 테이블로 구현하는것이 빠르다.

 

여기서는 회원테이블의 주민번호로 만나이를 구할때,
매번 주민번호 읽어서, 계산을 거치는 것보다는,
computed column 을 통해서 간단히 처리하는것이 좋다.

 

회원테이블에 FullAge 라는 computed column 을 아래와 같이 추가하면 끝이다.

 

-- 만나이컬럼: 계산된 열, 주민번호로 계산한다.


 

ALTER TABLE [회원테이블] ADD FullAge as (case when RegNo is null or RegNo = '' or CHARINDEX(' ', RegNo, 1) > 0 then 0 else
   CAST( Year(GetDate()) As Integer) - Cast(SubString((Case When SubString(RegNo, 8, 1) in ('1', '2', '5', '6') Then '19' + RegNo When SubString(RegNo, 8, 1) in ('3', '4', '7', '8') Then '20' Else '18' + RegNo End),1,4) as integer)
   - (case when Right('0' + cast(Month(GetDate()) as varchar), 2) + right('0' + cast(Day(GetDate()) as varchar), 2) > substring(RegNo, 3,4) then 0 else 1 end ) -- 만나이 계산, 생일이 안지났으면 1을 빼준다.
  end )


go

 

 

 

Posted by 헝개
개발팁2016. 7. 13. 12:00

jQuery 를 이용하여, AJAX 를 호출하는경우, 이미지를 표시하는 방법이다.

 

$.ajax 를 이용하여, 데이터를 불러오거나, 데이터를 저장할때,

작업시간이 많이 걸리는 경우에는, 로딩중임을 표시하는 이미지가 화면에 나타나도록 해준다.

 

 

 

여기서 사용한, 로딩이미지는 위의 이미지로, 마우스 오른쪽 버튼을 눌러서, 저장하여 사용해도 된다.

 

$.ajax({
       type: "POST"
       , contentType: "application/x-www-form-urlencoded"
       , url: "http://bemeal2.tistory.com/media/data"
       , data: "onLoad=%5Btype%20Function%5D&count=15&page=1"
       , async: true
       , error: function (res) {
              console.log("ajax error - " + res);
       }
       , success: function (res) {
              console.log("ajax success - " + res);
       }
       , beforeSend: function () {
              var width = 0;
              var height = 0;
              var left = 0;
              var top = 0;

              width = 50;
              height = 50;


              top = ( $(window).height() - height ) / 2 + $(window).scrollTop();
              left = ( $(window).width() - width ) / 2 + $(window).scrollLeft();

 

              if($("#div_ajax_load_image").length != 0) {
                     $("#div_ajax_load_image").css({
                            "top": top+"px",
                            "left": left+"px"
                     });
                     $("#div_ajax_load_image").show();
              }
              else {
                     $('body').append('<div id="div_ajax_load_image" style="position:absolute; top:' + top + 'px; left:' + left + 'px; width:' + width + 'px; height:' + height + 'px; z-index:9999; background:#f0f0f0; filter:alpha(opacity=50); opacity:alpha*0.5; margin:auto; padding:0; "><img src="file://D:\\temp\\ajax_loader.gif" style="width:50px; height:50px;"></div>');
              }

       }
       , complete: function () {
                     $("#div_ajax_load_image").hide();
       }
});

 

 

다른 코드는 기존 사용하던거 그대로 놓고, beforeSend 와 complete 만 가져가서 사용하면 된다.

beforeSend 는 AJAX 요청하기 전에 실행되며, complete 는 AJAX 응답이 완료되면, 오류던지 성공이던지 상관없이 호출이 된다.

 

 , beforeSend: function () {
              var width = 0;
              var height = 0;
              var left = 0;
              var top = 0;

 

              width = 50;
              height = 50;
              top = ( $(window).height() - height ) / 2 + $(window).scrollTop();
              left = ( $(window).width() - width ) / 2 + $(window).scrollLeft();

 

              if($("#div_ajax_load_image").length != 0) {
                     $("#div_ajax_load_image").css({
                            "top": top+"px",
                            "left": left+"px"
                     });
                     $("#div_ajax_load_image").show();
              }
              else {
                     $('body').append('<div id="div_ajax_load_image" style="position:absolute; top:' + top + 'px; left:' + left + 'px; width:' + width + 'px; height:' + height + 'px; z-index:9999; background:#f0f0f0; filter:alpha(opacity=50); opacity:alpha*0.5; margin:auto; padding:0; "><img src="file://D:\\temp\\ajax_loader.gif" style="width:50px; height:50px;"></div>');
              }

       }

 

img 태그의 src 속성은 실제 웹서버의 URL 로 변경해야한다.

로딩 이미지를 화면의 정 중앙에 보여주는 코드이다.

 

       , complete: function () {
                     $("#div_ajax_load_image").hide();
       }

 

AJAX가 완료되면, 로딩 이미지를 숨긴다. 이는 다음번 AJAX 호출이 될때 그대로 재사용하여, show() 메서드로 보여줄 수 있기에 감추기만 한 것이다.

 

 

 

실제 위 코드로 실행한 예이다.

 

 

 

하지만, $.ajax 를 작성시마다, 매번 위 코드를 복사해서 붙여넣기하는것은, 좋지 않은 방법인다.

 

common.js 파일을 만들어서, $.ajaxSetup 을 한번만 구현해 놓으면, 위의 코드를 매번 작성하지 않아도 된다.

 

 $.ajaxSetup({

... // 이 안에, beforeSend, complete. error 를 붙여넣으면 된다.

)};

 

Posted by 헝개
개발팁2016. 7. 11. 00:07

안드로이드 에뮬레이터인 AVD 에서 사용자 입력을 받는 키보드가
기본이 영문키보드라서 한글을 입력할수가 없다.

 

 

첨부된 hangulkeyboard.apk 받아서,
adb 명령을 실행하여, AVD 에 한글 키보드를 설치할 수 있다.

 

adb 명령은 윈도우의 CMD 창에서 하거나, 안드로이드 스튜디오의 왼쪽 하단에 Terminal 탭에서도 할수 있다.

실행전에, 안드로이드스튜디오에서 설치할 AVD 를 실행한 상태에서 실행해야 한다.


실행명령
adb install D:\Android\Hangulkeyboard.apk

 

path 설정이 안되었다면, 안드로이드 SDK 가 설치된 폴더로 이동해서 실행하면된다.

C:\Users\Administrator\AppData\Local\Android\sdk\platform-tools\adb install D:\Android\Hangulkeyboard.apk

 

 

 

Success 라고 나오면 설치가 왼료된것이나.


error: more than one device/emulator
만약 이와같은 오류가 나온다면, 디바이스를 선택하여, 설치를 해줘야 한다.

 

명령어
adb devices


를 치고 나오는 화면에서 설치할 디바이스 번호를 이와같이 입력해주면 설치가 완료된다.

adb -s emulator-5554 install D:\Android\Hangulkeyboard.apk


설치가 왼료가 되었으면, AVD 에서 한글 언어설정 및 한글 키보드를 설정해야 한다.

 

 

 

Settings -> Language & Input -> Language 를 한글로 변경한다.

 

 

 

 

설정 -> 현재키보드를 선택하고, 키보드 선택을 누르면, 설치된 한글접촉식 키보드가 보인다.

 

 


선택을 하고 뒤로가기를 한다.

 

다시, 설정 -> 현재키보드를 눌러보면,

 

키보드 종류에 영어(미국) 밑에 한글 접촉식 키보드가 보인다. 이를 선택하면, 한글 키보드 선택이 완료된다.

 

 

 

 

hangulkeyboard.apk

 

Posted by 헝개
개발팁2016. 7. 6. 10:52

TabControl 은 C# Winform 의 컨테이너에 속해있다.

하나의 TabControl 하위에는 여러개의 TabPage 컨트롤을 포함한다.

 

TabPage 의 타이틀에는 기본적으로 문자로 표현이 되지만, 이미지를 넣는 방법이 있다.
ImageList 라는것을 이용하는 방법이다

 

Visual Studio 의 도구상자의 구성요소에 보면 ImageList 라는것이 있다.
이를 더블클릭하면,


디자인창의 하단부분에 ImageList 컨트롤이 생성이 되는것을 볼 수 있다.
View 가 없는 컨트롤이기 때문에 뷰의 하단에 나타난다.

 

 

 

생성된 ImageList 를 선택하여, 속성을 보면,
ColorDepth, ImageSize 를 설정할 수 있다.

 

 

그리고, ImageList 에 실제 이미지를 등록할수 있는 Images 컬렉션이 보인다.
이를 클릭하여, PC에 저장된 이미지를 ImageList 로 등록을 할 수 있다.

이렇게 등록된 ImageList 를 TabControl 과 TabPage 에 연결을 하면, 탭페이지에 이미지가 나타나게 된다.

 

 

 

우선, 디자인에서 TabControl 을 선택하여, 속성을 보면,
ImageList 라는 속성이 있다, 이곳을 클릭해보면, 아까 추가했던 ImageList  목록이 보인다.
원하는 항목을 선택하고,

 

다음으로, TabPage 를 선택하여, 속성을 보면, ImageIndex 라는 속성을 볼 수 있다.
이곳에서 원하는 이미지를 선택하면, 아이콘 처럼, 탭페이지 타이틀 옆에 이미지가 나타나게 된다.

 

 

또한, TabPage 의 타이틀인 Text 속성의 값을 모두 지워버리고,
ImageList 등록할때 ImageSize 를 크게 지정을 하면, 이미지로만 구성된 탭페이지 타이틀을 볼 수 있다.

 

 

TabPageExample.zip

 

Posted by 헝개