GridView, ListView에 있는 SelectedItems 프로퍼티는 바인딩이 되지 않는다. 그래서, 바인딩 가능한 Behavior를 만들어 보았다.

Windows 8.1 Moden App에서 테스트를 했는데, Windwos 8에서도 가능하리라 생각된다.

 

참고 포스트

Behaviors in Windows 8.1 Store Apps

http://www.julmar.com/blog/programming/behaviors-in-windows-8-1-store-apps/

 

1. Behavior(08-05-2015 update)

 

public class SelectedItemsBehavior : DependencyObject, IBehavior

{

/// <summary>

/// 비헤이비어에 붙어있는 프로퍼티

/// </summary>

public static readonly DependencyProperty SelectedItemsProperty =

DependencyProperty.Register("SelectedItems", typeof (object), typeof (SelectedItemsBehavior),

new PropertyMetadata(null, OnSelectedItemsChanged));

/// <summary>

/// 이벤트 중복 방지

/// </summary>

private readonly object _isLock = new object();

/// <summary>

/// IsBusy

/// </summary>

private bool _isBusy;

/// <summary>

/// 뷰 모델의 프로퍼티 - 반드시 object로 만든다. 다른형은 프로퍼티 추가가 않된다.

/// </summary>

public object SelectedItems

{

get { return GetValue(SelectedItemsProperty); }

set { SetValue(SelectedItemsProperty, value); }

}

/// <summary>

/// 연결되어있는 오브젝트

/// </summary>

public DependencyObject AssociatedObject { get; private set; }

/// <summary>

/// Listview에 연결 될때 실행되는 메소드

/// </summary>

/// <param name="associatedObject"></param>

public void Attach(DependencyObject associatedObject)

{

if ((associatedObject != AssociatedObject) && !DesignMode.DesignModeEnabled)

{

if (AssociatedObject != null)

throw new InvalidOperationException("Cannot attach behavior multiple times.");

AssociatedObject = associatedObject;

var control = AssociatedObject as ListViewBase;

if (control == null)

{

throw new InvalidOperationException("Cannot attach behavior you must have ListViewBase.");

}

//SelectedItems가 Runtime Object임

control.SelectionChanged += control_SelectionChanged;

}

}

/// <summary>

/// ListView 연결 해제될때 실행되는 메소드

/// </summary>

public void Detach()

{

if (SelectedItems != null)

{

((INotifyCollectionChanged) SelectedItems).CollectionChanged -= ViewModelToControl_CollectionChanged;

}

if (AssociatedObject != null)

{

((ListViewBase) AssociatedObject).SelectionChanged -= control_SelectionChanged;

}

AssociatedObject = null;

}

/// <summary>

/// 컨트롤에 변경 사항을 뷰모델로 반영

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void control_SelectionChanged(object sender, SelectionChangedEventArgs e)

{

lock (_isLock)

{

if (_isBusy) return;

_isBusy = true;

}

var control = AssociatedObject as ListViewBase;

if (control == null) return;

var list = SelectedItems as IList;

if (list == null) return;

if (e.AddedItems != null && e.AddedItems.Any())

{

foreach (var addedItem in e.AddedItems)

{

var existIndex = list.IndexOf(addedItem);

if (existIndex == -1)

list.Add(addedItem);

}

}

if (e.RemovedItems != null && e.RemovedItems.Any())

{

foreach (var removedItem in e.RemovedItems)

{

var existIndex = list.IndexOf(removedItem);

if (existIndex > -1)

list.Remove(removedItem);

}

}

_isBusy = false;

}

/// <summary>

/// 비헤이비어 프로퍼티 체인지 이벤트

/// </summary>

private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

var source = (SelectedItemsBehavior) d;

//이전 프로퍼티에 붙어있던 이벤트 제거

var oldCollection = e.OldValue as INotifyCollectionChanged;

if (oldCollection != null)

{

oldCollection.CollectionChanged -= source.ViewModelToControl_CollectionChanged;

}

//새 프로퍼티에 이벤트 연결

var newCollection = e.NewValue as INotifyCollectionChanged;

if (newCollection != null)

{

newCollection.CollectionChanged += source.ViewModelToControl_CollectionChanged;

}

}

/// <summary>

/// 뷰모델의 프로퍼티에서 발생한 이벤트를 이용해서 컨트롤에 작업

/// </summary>

private void ViewModelToControl_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)

{

lock (_isLock)

{

if (_isBusy) return;

_isBusy = true;

}

var control = AssociatedObject as ListViewBase;

//Reset처리

if (e.Action == NotifyCollectionChangedAction.Reset)

{

if (control == null) return;

control.SelectedItems.Clear();

}

//삭제된 아이템 처리

if (e.OldItems != null)

{

foreach (var item in e.OldItems)

{

if (control != null && control.SelectedItems.Contains(item))

{

control.SelectedItems.Remove(item);

}

}

}

//추가된 아이템 처리

if (e.NewItems != null)

{

try

{

foreach (var item in e.NewItems)

{

if (control != null && control.SelectedItems.Contains(item) == false)

{

control.SelectedItems.Add(item);

}

}

}

catch (OutOfMemoryException ome)

{

EtcHelper.Instance.MsgBox(ome.Message);

}

catch (Exception ex)

{

Debug.Assert(false, ex.Message);

}

}

_isBusy = false;

}

}

 

2. XAML

 

            <ListView x:Name="listView" Grid.Row="1" ItemsPanel="{StaticResource HItemsPanelTemplate}" SelectionMode="Multiple"
       ItemsSource="{Binding SelectedImage.ItemImages}" >
             <Interactivity:Interaction.Behaviors>
              <Behaviors:SelectedItemsBehavior SelectedItems="{Binding SelectedItemImages}"/>
             </Interactivity:Interaction.Behaviors>

    <ListView.ItemTemplate>
     <DataTemplate>
      <Grid>
       <Image Source="{Binding WorkedImage}"/>
       <StackPanel VerticalAlignment="Bottom" Background="{StaticResource DefaultImageTextBackgroundBrush}" >
        <TextBlock Style="{StaticResource DetailTitleStyle12}" Margin="5,10,0,5">
            <Run Text="{Binding FileName}"/>
            <Run Text="{Binding ExtName}"/>
        </TextBlock>
       </StackPanel>
      </Grid>
     </DataTemplate>
    </ListView.ItemTemplate>
   </ListView>


 

3. ViewModel

 

        private ICollection<FileInfoM> _selectedItemImages;
        /// <summary>
        /// 선택된 아이템들
        /// </summary>
        public ICollection<FileInfoM> SelectedItemImages
        {
            get { return _selectedItemImages; }
            set { _selectedItemImages = value; OnPropertyChanged(); }
        }

 

...

생성자에서 인스턴스

SelectedItemImages = new ObservableCollection<FileInfoM>();

...

 

        private DelegateCommand _selectAllCommand;
        /// <summary>
        /// Select All Command
        /// </summary>
        public DelegateCommand SelectAllCommand
        {
            get
            {
                return _selectAllCommand = _selectAllCommand ?? new DelegateCommand(
                args =>
                {
                    if (SelectedItemImages.Count != SelectedImage.ItemImages.Count)
                    {
                        foreach (var item in SelectedImage.ItemImages)
                        {
                            SelectedItemImages.Add(item);
                        }
                    }
                    else
                    {
                        foreach (var item in SelectedImage.ItemImages)
                        {
                            SelectedItemImages.Remove(item);
                        }
                    }
                });
            }
        }

 

4. 작업 화면

 

SelectAll 버튼을 클릭해서 하단의 2개 아이템 선택

 

전체 선택이 된 상태에서 다시 하번 누르면 선택 해제

 

5. 앱 개발이 마무리 단계라 소스를 올리지 못했는데, 나중에 요청이 있으면 간단한 셈플을 만들어서 올리도록 하겠다. 실버라이트용 Behavior는 약간 다르지만 기본적인 내용은 동일하니 참고해서 만들면 된다.

 

블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

MTProto Mobile Protocol

 

https://core.telegram.org/mtproto

 

General Description


이 프로토콜은 모바일 디바이스에서 서버로 접근하는 API로 디자인 되었다. 웹 브라우저에서 사용하는 것이 아님을 강조한다.

이 프로토콜은 3개의 독립된 컴포넌트로 세분화 되어 있다.
. 하이레벨 컴포넌트(API query language) : API쿼리와 메시지가 바이너리로 변환된 내용이 정의 되어 있다.
. 암호화 계층(인증) : 전송되기 전에 암호화된 메시지의 내용이 정의 되어 있다.
. 전송 컴포넌트 : 클라이언트와 서버간의 전송을 위해 다른 기존의 네트워크 프로토콜(예: http, https, tcp, udp)에 대한 내용이 정의되어 있다.

 

노트 1:
일반 텍스트 메시지를 MTProto에서 항상 암호화하고, 시스템 구성 요소와 알려진된 문제에 대해 강력하도록 암호 해독 시 검사할 다음 데이터를 포함한다.
•server salt (64-Bit) : 서버슬랫
•session id : 세션아이디
•message sequence number : 메시지 순번
•message length : 메시지 길이
•time : 시간

 

노트 2:
추가 커맨트를 보려면 링크 클릭

 

 

Brief Component Summary : 구성 요소 요약
High-Level Component (RPC Query Language/API) : 하이레벨 컴포넌트
하이레벨 컴포넌트 관점에서 보면, 클라이언트와 서버 세션안에서 메시지 교환하는 것이다.
세션은 특정 http/https/tcp 연결 보다는 오히려 클라이언트 장치 (더 정확 하 게, 응용 프로그램)에 연결 된다.
또한, 각 세션은 실제 인증완료된 사용자 키 ID에 연결되어 있다.

여러 서버에 연결을 열릴 수 있고, 메시지는 어떤 컨넥션이든지 양방향으로 전송이 가능하다.
(응답은 동일한 연결을 통해서 반환되지 않을 수 있으며, 자주 발생하는 경우이다. 그러나, 다른 세션을 통해서라도 메시지가 반환 될 수 있다.)
UDP 프로토콜을 사용하는 경우 응답 쿼리가 다른 IP 주소에 의해 반환 될 수 있다.

몇개의 메시지 유형
•RPC calls (client to server): 클라이언트가 서버 API호출
•RPC responses (server to client): 클라이언트 호출에 대한 결과 반환
•Message received acknowledgment (or rather, notification of status of a set of messages) : 메시지 수신 승인(또는 알림 메시지 집합)
•Message status query : 메시지 상태 쿼리
•Multipart message or container (a container that holds several messages; needed to send several RPC calls at once over an HTTP connection, for example; also, a container may support gzip).
멀티파트 메시지 또는 컨테이너(컨테이너는 여러개의 메시지를 홀드 할 수 있고, 서버로 한번에 보낼 수 있다. 예를 들어 컨테이너가 gzip을 지원하는 경우다)

 

낮은 레벨 프로토콜의 관점에서 메시지는 이진 데이터 스트림 4 또는 16 바이트 경계에 따라 정렬된다.
메시지의 첫부분 몇 가지 필드는 암호화/인증 시스템에 의해 사용되도록 고정되어있다.

각 메시지는, 독립적이거나 컨테이너 내부는 메시지 식별자(64비트, 아래 참조), 메시지 세션의 순번(32비트), 길이(바이트;메시지 본문의 길이 32비트), 본체(4바이트의 배수)로 구성되어진다.
또한, 컨테이너 또는 단일 메시지를 보낼 때 내부 헤더가 상단에 추가 되고(아래 참조), 메시지가 암호화되고, 외부헤더가 메시지 상단에 들어 갑니다.(64-비트 키 식별자와 128-비트 메시지 키)

메시지 본체는 일반적으로 종속 매개 변수 뒤에 32비트 메시지 유형으로 구성되어있고,
특히 각 RPC 함수는 해당 메시지 유형이 있다. 자세한 사항은 링크 참고

모든 숫자는 리틀 엔디안으로 작성 된다. 그러나, 매우 큰 숫자 (2048 비트) RSA와 DH는 큰 endian 형식으로 작성 된다. 왜냐하면 OpenSSL 라이브러리이기 때문이다.

 

Authorization and Encryption : 인증과 암호화

 

이전 메시지 (또는 다중 파트 메시지) 전송 프로토콜을 사용 하여 네트워크를 통해 전송 되고, 암호화된 외부 헤더는 메시지의 위쪽에 추가 된다. 암호화된 내용은 64-비트 키 식별자 (고유 하 게 식별 인증 키 서버 뿐만 아니라 사용자에 대 한) 및 128 비트 메시지 키이다. 사용자키와 메시지키 256비트 키를 정의하고, 실제 메시지를 AES-256 방식으로 암호화한다.
메시지 암호화의 초기 부분 메시지 키(및 그러므로 AES 키 및 iv)와 명백 하게 영향을 미치는 변수 데이터(세션, 메시지 ID, 시퀀스 번호, 서버 소금) 포함 되어 있있다. 메시지 키가 메시지 본문의 SHA1 128 하위 비트로 정의 (포함 한 세션, 메시지 ID, 등.). 다중 파트 메시지를 단일 메시지 암호화

기술 사양에 대한 모바일 프로토콜(링크)을 참조

클라이언트 응용 프로그램이 처음으로 해야하는 것은 인증키를 생성해야한다. 일반적으로 이 과정은 변하지 않는다.

 

프로토콜의 주요한 결점은 침입자가 수동적으로 메시지를 차단하고, 어떻게든 인증키(예를 들어 장치를 훔쳤을 때)를 도용하여 메시지를 가로체고 해독할 수 있다. 아마도 이건 너무 많은 문제(장치를 훔치면 저장된 모든 정보를 모두 해독할 수 있다)를 가지고 있다. 그러나, 이 약점을 극복하기 위해 다음 단계를 수행하면 된다.

 

* 세션키는 Diffie-Hellman 프로토콜에 의해 생성하고, 인증과 메시지키는 AES 파라메터에서 선택해서 사용한다.
이 것을 만든 후 클라이언트는 첫번째로 새로운 세션을 생성하고 RPC서버로 전송하면, 서버가 생성된 세션키를 반환해준다.그 후 모둔 후속 메시지는 세션 키를 사용하여 암호화 된다.

 

* 클라이언트 장치에 저장된 키를 택스트 암호로 보호한다. 이 패스워드는 메모리에 저장되지 않고 사용자에 응용프로그램이 시작될 때 입력 받는다.

 

* 사용자 장치에 저장된 데이터 또한 인증키를 이용해서 암호화해서 보호해야 한다. 패스워드는 그 데이터에 접근할 때도 필요하다

 

Time Synchronization : 시간 동기화

 만약 클라이언트 시간과 서버 시간이 차이가 많이 난다면, 서버는 클라이언트 메시지를 무지하거나, 그 반대의 경우가 발생할 수 있다. 왜냐하면, 메시지 식별자가 잘못되었기 때문이다(생성시간과 밀접한 관련이있다)

이러한 상황에서 서버는 클라이언트에게 정확한 시간을 포함하는 특별한 메시지와 128-bit salt를 보낸다.
(클라이언트 특정 RPC 동기화 요청을 받거나 현재 세션 중에 받은 마지막 메시지의 키와 같은지 비교해서 명시적으로 제공한다.)

이 메시지는 다른 메시지를 포함하는 컨테이너의 첫번째가 될 수 있다.(시간 차이가 중요하지만 클라이언트의 메시지가 발생하지 않은 경우 무시된다.)

 

그러한 메시지 또는 그것을 포함한 컨테이너를 수신한 경우, 클라이언트는 우선 시간 동기화를 수행(서버시간과 미래의 올바른 시간을 계산하고 차이를  이용해서 보정)하고 메시지 식별자가 정확한지 검사한다.

 

보정이 무시 경우, 클라이언트는 메시지 식별자 단순성을 보장하는 새로운 세션을 생성한다.

 

Transport : 전송

클라이언트에서 서버로나 그 반대로 암호화된 컨테이너와 외부 헤더(이하 페이로드)의 전달이 가능하다. 세가지 전송 타입이 있다.
. HTTP

. TCP

. UDP
우선 두가지 종류를 살펴보자

 

HTTP Transport

HTTPS를 사용하지 않고 기존의 TCP 포트 80을 이용하는 HTTP/1.1(with keepalive)로 구현; 위의 암호화 방법이 대신 사용된다.

 

HTTP 연결은 가장 최근에 수신된 사용자 쿼리에 지정된 세션(아니면 세션 + 키 식별자)에 붙어있다. 일반적으로 세션은 모든 쿼리에서 동일하지만, HTTP 프록시에 의해 손상될 수 있다. 서버는 HTTP 연결에서 동일한 세션이 아니거나, 서버의 차례가 아니면 메시지를 반환하지 않는다.(클라이언트의 HTTP 요청을 받고 응답을 하지 않은 상태)

다음은 전반적인 사항이다. 클라이언트는 서버에 하나 이상의 keepalive HTTP 연결을 연다.만약 하나나 그 이상의 메시지를 보내야 하는 경우, POST 요청을 포함하는 페이로드를 만들고 전송한다. 페이로드에는 컨텐츠길이, Keepalive와 호스트의 유효한 HTTP헤더를 추가한다.

 

쿼리를 수신하면, 서버는 조금 기다리거나(만약 쿼리가 짧은 타임아웃 응답을 요구하면) 즉시 더미 응답(오직 컨터이너가 인정된 경우)을 반환한다. 어떤 경우에는, 응답 메시지에 임의의 수를 포함 할 수있다. 서버는 동시에 세션에서 홀딩 중이던 다른 메시지를 전송할 수 있다.

 

또한, 최대 전송 타임아웃 T가 지정된 특정 long poll RPC쿼리(유효한 HTTP 연결만 가능)가 존재한다. 일반적으로 서버가 세션에 메시지를 가지고 있다면 즉시 반환한다. 그러나 long poll RPC쿼리가 존재하면, T second가 흐르기 전까지 서버는 메시지를 대기 상태로 만든다. 만약 T seconds가 흐른 후 이벤트가 발생하지 않으면 더미 응답을 반환한다(특별 메시지).

 

만약, 서버가 클라이언트에서 메시지를 보내야할 필요가 있다면, 필요 세션과 "HTTP 요청에 응답가능" 상태, HTTP연결을 확인하고, 메시지를 응답 컨테이너에 넣은 후 사용자에게 보낸다. 전형적으로 서버에서 또 다른 메시지를 보내기 위해서는 추가 시간(50밀리세컨드)이 필요하다. 

 

만약 어떤 적합한 HTTP 연결을 사용할 수 없다면, 메시지는 현재 세션의 송신 큐에 담긴다. 그러나, 그 메시지들은 명시적이든 간접적으로 클라이언트에 확인될 때까지 어떻게든 자신의 길을 찾는다. HTTP 프로토콜에서, 동일한 HTTP 연결안에서 다음 쿼리를 전송하면 암묵적 확인 응답으로 간주한다.(아무것도 없다면 HTTP 프로토콜은 명시적 승인을 요청을 보낸다), 다른 경우에, 클라이언트는 일정 시간 내에 명시적 확인 응답을 반환해야한다(그것이 다음 요청을 컨터이너에 추가할 수 있다)

 

중요 : 만약 응답 시간에 승인 메시지가 도착하지 않을 경우, 메시지를 재정송할 수 있다.(다른 컨테이너를 이용해서). 당사자들은 자율적으로 이에 대한 준비를해야하고, 가장 최근의 수신된 메시지 식별자를 저장해야한다.(반복된 동작에 의해 발생되는 중복은 무시) 저장된 영원한 식별자는 가질 수 없기 때문에, 메시지 식별자의 단순성을 활용 특수 가비지 컬력션 메시지가 존재한다.

만약 송신 큐가 오버플로우가 발생하거나 메시지가 큐에 10분이상 남아있다면 서버는 그것들을 지운다.(아니면 스왑한다.) 이 것은 서버의 버퍼 공간이 부족한 경우 더 빠르게 발생할 수 있다.(예를 들어 네트워크 이슈가 발생했다거나 할 때)

 

TCP Transport

이것은 HTTP 전송과 매우 유사하다. 또한 포트 80(모든 방화벽을 통과하기 위해)과 동일한 IP 어드레스를 사용한다. 이 상황에서, 서버는 HTTP또는 TCP프로토콜 중 어떤 것을 사용해야하는지 처음 4바이트를 기준으로 판단한다.(HTTP POST방식)

 

TCP연결이 생성되면, 이 세션(과 인증키)을 사용자 메시지 전송에 할당하고, 이어서 독점적으로 이용한다.(다중화 배열이 허용되지 않는다)

 

만약 페이로드가 서버에서 클라이언트, 혹은 클라이언트에서 서버로 전송될 필요가 있는 경우에 다음과 같이 캡슐화: 4바이트(길이, 순번, CRC32;4로 나누어지는)를 앞에 추가, TCP 컨넥션에서의 패킷 순번 4바이트(처음건 0, 다음은 1..), 4 CRC32 바이트(길이, 순번, 페이로드)를 뒤에 추가

 

동일한 프로토콜의 축소된 버전이 있다: 만약 클라이언트가 0xef를 첫번째 바이트로 보내면(**중요** 첫데이터 패킷이전에), 패킷 길이는 암호화 된다.(0x01..0x7e = 데이터 길이는 4로 나누거나 0x7f 다음 3바이트를 4로 나눈). 이 경우 서버는 동일한 응답을 보낸다.

 

프로토콜의 전체 및 축소 버전의 빠른 응답을 지원해야한다. 이 경우, 클라이언트는 질의 패킷에서 가장 높은 차수 비트 길이를 설정하고, 서버는 개별 패킷의 특정 4바이트로 응답한다. 그것들은 정규 서버 응답 패킷이 아니라는 것을 명확하게 설정하는 최상위 비트를 가진 패킷의 암호화 부의 고차 SHA1비트이다; 축소 버전의 경우 4바이트에 적용된다.

 

TCP 전송에에는 묵시적 승인은 없다 : 모든 메시지를 명시적으로 승인해야한다: 컨테이너나 응답을 빠르게 승인해야한다. 예를 들어 거의 항상 RPC쿼리를 포함하는 클라이언트 메시지 : 확인 응답은 보통 RPC 응답으로 처리

 

에러가 발생하면, 서버는 페이로드 에러 코드로 4 바이트로 구성 패킷을 전송할 수있다. 예를 들어, 오류 코드 (403)는 해당 HTTP 에러가 HTTP 프로토콜에 의해 반환 될 상황에 대응한다.

'Windows 8&8.1 > ETC' 카테고리의 다른 글

MTProto Mobile Protocol 번역 중  (2) 2014.06.03
Image Note  (0) 2014.05.12
Now FocusedElement, CurrentPage  (0) 2013.08.29
Custom ConfirmBox create  (0) 2013.08.21
patterns & practices: Prism for the Windows Runtime  (0) 2013.07.10
Microsoft .Net Framework 4.5 Quickstart Cookbook Review  (0) 2013.07.05
블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

디아블로3 아이템 자랑은 Screenshot AutoCut로!

앤유 사이트에 올라온 기사 스크랩 입니다.

http://www.nyou.kr/%eb%94%94%ec%95%84%eb%b8%94%eb%a1%9c3-%ec%95%84%ec%9d%b4%ed%85%9c-%ec%9e%90%eb%9e%91%ec%9d%80-screenshot-autocut%eb%a1%9c/

 

블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

Image Note

Windows 8&8.1/ETC 2014.05.12 23:53

간단하게 이미지의 스케일을 변경한다. Bound와 Flip 등의 기능이 가능, 예제에서 찾아서 남김

 

        private async void OnDeferredImageRequestedHandler(DataProviderRequest providerRequest, StorageFile imageFile)
        {
            // In this delegate we provide updated Bitmap data using delayed rendering.

            if (imageFile != null)
            {
                // If the delegate is calling any asynchronous operations it needs to acquire the deferral first. This lets the
                // system know that you are performing some operations that might take a little longer and that the call to
                // SetData could happen after the delegate returns. Once you acquired the deferral object you must call Complete
                // on it after your final call to SetData.
                DataProviderDeferral deferral = providerRequest.GetDeferral();
                InMemoryRandomAccessStream inMemoryStream = new InMemoryRandomAccessStream();

                // Make sure to always call Complete when done with the deferral.
                try
                {
                    // Decode the image and re-encode it at 50% width and height.
                    IRandomAccessStream imageStream = await imageFile.OpenAsync(FileAccessMode.Read);
                    BitmapDecoder imageDecoder = await BitmapDecoder.CreateAsync(imageStream);
                    BitmapEncoder imageEncoder = await BitmapEncoder.CreateForTranscodingAsync(inMemoryStream, imageDecoder);
                    imageEncoder.BitmapTransform.ScaledWidth = (uint)(imageDecoder.OrientedPixelWidth * 0.5);
                    imageEncoder.BitmapTransform.ScaledHeight = (uint)(imageDecoder.OrientedPixelHeight * 0.5);

                    await imageEncoder.FlushAsync();

                    providerRequest.SetData(RandomAccessStreamReference.CreateFromStream(inMemoryStream));
                }
                finally
                {
                    deferral.Complete();
                }
            }
        }

 

'Windows 8&8.1 > ETC' 카테고리의 다른 글

MTProto Mobile Protocol 번역 중  (2) 2014.06.03
Image Note  (0) 2014.05.12
Now FocusedElement, CurrentPage  (0) 2013.08.29
Custom ConfirmBox create  (0) 2013.08.21
patterns & practices: Prism for the Windows Runtime  (0) 2013.07.10
Microsoft .Net Framework 4.5 Quickstart Cookbook Review  (0) 2013.07.05
블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

오래전에 올렸던 앱을 다시 빌드해서 스토어에 올릴려고 하는데 오류가 발생했다.

Windows Store Apps, Error: The certificate specified has expired

 

구글에서 아래 블로그의 내용을 찾았다.

http://mark.mymonster.nl/2013/10/07/windows-store-apps-error-the-certificate-specified-has-expired

 

위의 내용대로 따라하기를 했으나, 약간의 오류가 더 있어서 찾아보니 Publisher 이름이 틀리다고 나온다.

이미 배포가 된 앱이였기 때문에 앱 스토어에 올릴때 사용했던 이름을 사용해야 한다.

 

Publisher Common Name

입력하는 부분에 스토어에 등록되어 있는 나의 Publisher Name을 입력해야한다.

예)

CN=0F14119E-BE6D-47B8-9677-XXXXXXXXXXXX

로 되어있는 부분에서 CN=를 제외한 나머지 부분을 입력하고 비밀번호를 입력해서 Test Certificate를 만들어 주어야한다.

 

블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

리소스를 이용해서 문자열 작업할 때 사용하는 방법이다.

 

1. DynamicResource

    /// <summary>
    /// 다이나믹 리소스
    /// </summary>
    public class DynamicResource : DynamicObject
    {
        /// <summary>
        /// 윈도우 리소스로더
        /// </summary>
        Windows.ApplicationModel.Resources.ResourceLoader _rl;

        /// <summary>
        /// 리소스 전체 이름
        /// </summary>
        public string ResourceName { get; set; }

        /// <summary>
        /// 이름으로 호출
        /// </summary>
        /// <param name="binder"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            string str = string.Empty;
            if (Windows.ApplicationModel.DesignMode.DesignModeEnabled == false)
            {
                if (_rl == null)
                {
                    _rl = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView(ResourceName);
                }

                str = _rl.GetString(binder.Name);
                if (string.IsNullOrEmpty(str) == true)
                {
                    str = string.Empty;
                }
            }
            else
            {
                str = binder.Name;
            }
            result = str;
            return true;
        }

        /// <summary>
        /// 프로퍼티로 호출
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public string this[string id]
        {
            get
            {
                string str = string.Empty;
                if (Windows.ApplicationModel.DesignMode.DesignModeEnabled == false)
                {
                    if (_rl == null)
                    {
                        _rl = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView(ResourceName);
                    }

                    str = _rl.GetString(id);
                    if (string.IsNullOrEmpty(str) == true)
                    {
                        str = string.Empty;
                    }
                }
                else
                {  
                    //디자인 타임에서는 키값을 반환
                    str = id;
                }
                return str;
            }
        }
    }

 

2. App.xaml

xmlns:CPCommons="using:CrossPlatform.Infrastructure.StoreApp.Commons"

...

 

<CPCommons:DynamicResource x:Key="DResource" ResourceName="ScreenshotAutoCut.PCL.en.UIResources"/>

 

3. xaml에서 사용하기

 

      <TextBlock Style="{StaticResource SubheaderTextBlockStyle}" Grid.Row="1" Margin="0,10,0,0" TextWrapping="Wrap"
       Text="{Binding [tx_please_add_screenshots_folder], Source={StaticResource DResource}}"/>
      <TextBlock Style="{StaticResource TitleTextBlockStyle}" Grid.Row="2" Margin="0,10,0,0"
       Text="{Binding [tx_description], Source={StaticResource DResource}}"/>
      <TextBlock Style="{StaticResource BodyTextBlockStyle}" Grid.Row="3"
       Text="{Binding [tx_click_the_add_folder_button], Source={StaticResource DResource}}" >

4. cs에서 사용하기

            //리소스 타입 입력 - dynamic 키워드가 중요
            dynamic DR = App.Current.Resources["DResource"];

            var test = DR.tx_please_add_screenshots_folder;

         System.Diagnostics.Debug.WriteLine(test);


 

블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

앱 개발 후 수익 모델로 가장 쉽게 사용할 수 있는 것이 광고를 추가하는 방법이다.

이 포스트에서 간단하게 내가 사용하고 있는 광고 종류와 붙이는 방법에 대해서 간단히 설명하도록 하겠다.

 

1. AdDuplex

http://adduplex.com/

기본 컨셉은 내 앱에서 다른 앱 광고를 해주고, 다른 앱에서 내 앱을 광고해주는 앱 광고를 서로 나누면서, 다운로드 수를 올리기 위해 사용된다.

 

가입 후 새로운 앱을 등록하면 아래와 같은 화면이 나온다.

 

 

위에서 App ID가 앱에서 입력해야하는 코드이다. 보안상 코드값은 삭제했다.

 

단계별로 어떻게 해야하는지 정리가 되어있기 때문에 그대로 따라하면 된다.

1. Add app title : 앱 제목과 기본 광고 문구를 입력한다.

2. Create a banner : 기본 광고 문구가 표시되면서 각 크기별로 내용을 수정할 수 있다. 기본은 택스트만 지원하며, 이미지는 별도록 사이즈별로 제작해서 넣으면 된다.

3. Add AdDuplex SDK : SDK를 앱에 추가하는 방법에 대해서 설명이 나온다.

 

 

각 사이즈별로 내가 입력한 광고 문구가 미리 표시가 된다. 내용이 너무 많아서 여러줄이 되어서 크기를 벗어나면 각 사이즈 별로 문구를 수정해서 내용을 정리할 수 있다.

 

2. 솔루션에 AdDuplex SDK 추가하기

솔루션에서 마우스 오른쪽 버튼을 클릭해서 Managed Nuget Packages를 선택 -> Online -> adduplex 검색어 입력 -> AdDuplex SDK for Windows8 (Xaml edition)을 선택한다.

 

 

 

이제 프로젝트에서 사용할 준비가 완료된 것이다.

 

3. 화면에 광고 표시하기

xaml에 namaspace추가

 

xmlns:ad="using:AdDuplex.Controls"

 

Hub컨트롤에 하나의 HubSection에 AdControl추가

 

   <HubSection>
    <DataTemplate>
     <Grid>
      <ad:AdControl Size="160x600" AppId="[위에서 발급받은 App ID입력]" Margin="0,-15,0,0"/>
     </Grid>
    </DataTemplate>
   </HubSection>

 

AdControl에서 중요한 프로퍼티는 2가지이다. Size와 AppId 이 두가지를 꼭 선택해야 광고가 제대로 표시 된다.

(HubSection이라 Margin을 -15를 주어야 하단이 짤리지 않음, Margin은 화면의 구성에 따라 다름)

 

 

 

개발 도중에도 광고가 계속 나오는 걸 알 수 있다.

 

4. 마지막으로 가장 중요한 Activate

이렇게 해서 개발을 완료 후 스토어에 정식으로 등록이 되면, 앱이 등록된 주소를 AdDuplex사이트에서 입력해 주어야 한다. 입력하고 몇일 후에 정식으로 Activate가 되면, 그 때부터 내 앱에 대한 광고가 다른 앱에 표시가 된다.

 

아래는 현재 Activate가 되어 있는 앱이다. 화면에서와 같이 Running 표시가 되어야 한다.

 

 

5. AdDuplex는

직접적인 수익이 발생하는 것이 아니라 내 앱을 광고하기 위해 사용한다. 그래서, 직접적인 수익이 발생하는  Microsoft Advertising SDK for Windows 8을 메인 광고로 넣어야 한다. 이 부분에 대해서는 다음에 포스팅 하도록 하겠다.

 

 

블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

Screenshot AutoCut Privacy Policy

 

KakiSoft's privacy policy guide

 

We do not store any of your personal information.

Favorite folder and item image information is stored only in Windows 8 local storage.

 

Diablo III, Diablo III Reaper of Souls is is a registered trademark of Blizzard Entertainment, and some images are copyright of Blizzard Entertainment, Inc.

 

 

Thank you for your visit

 

kaki104

블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

 

Screenshot AutoCut

 

Diablo 3 gameplay in "The Legend items" when you pick up, you are proud of this one in order to save the screen shot, you run the Paint program and recall it, the item selection part, copy, and store after use the.

 

However, this app allows users to save the "screenshot" of the item is automatically locate the part, cut, showing a list of items, and then save the selected item, Share functions using facebook, email to share or that, in the copy function within the app to copy and paste when writing immediately after performing an item and easily helps you to share images.

 

If you cut out the image if the item you have ever, just using a paint program, but that number is often bothersome side Maybe it'll work?

This app is for those gamers app.

 

 

* Other helps

Korean help

디아블로 3 인벤 팁게시판

 

* Support game

Diablo III

 

* Download link

http://apps.microsoft.com/windows/app/screenshot-autocut/8e418c94-6ea1-4912-bf33-f28eac48ea2f

 

* Feature

* [New] Use OneDrive upload item images, and create links to the shared

* Item image in the screenshot gives automatically find and cut.

* Item images 'My picture folder' save.

* Item Image using the Windows share in the Share function.

* Screenshot of others in 'Item Image' to find and save the cut.

* Many 'Item Image' manage by using folder.

* 'Screenshot', 'Item Image' delete function

* Item image upload OneDrive

 

* Version history : 1.2.1

1. Add function to upload images to OneDrive

2. Add function generating a link to the uploaded image sharing OneDrive

 

* Version history : 1.2
1. Add Share target function :
If your browser displays the screenshot of Diablo, then find a desktop screenshot images available items

2. Add folder management
Many "Item Image" accessories, armor, weapons, etc., go to the folder can be managed

3. Add sound effects

 

1. Start Screen 

 

 

2. Add screenshot folder

 

Refresh Items button : refresh item images

Add Folder button : add screenshot folder

 

3. Select screenshot folder

Diablo 3 Screenshots default folder is "C:\Users\[USER NAME]\Documents\Diablo III\Screenshots" position.

 

 

4. Navigate folder detail page, Looking for an item in the screenshot image, please wait ...

Select screenshot image

 

5. Item image find success, select item images

 

Refresh Images button : refresh screenshot list

Delete Image button : delete selected image

Remove Folder button : remove folder from favorite list

Select All button : select all item images / unselect all item images

Save button : save the item image in "C:\Users\[USER NAME]\Pictures\Screenshot AutoCut" folder

Share button : share saved item images

 

 

6. Back to start screen

Click to item image

 

7. Navigate to ITEMS page

 

 

Create Folder button : create new folder in picture folder

Delete Folder button : delete select folder (Accessories, Armors, Weapons folder is default)

Delete File button : delete select files

Copy File button : select item image copy to clipboard

Share button : share saved item images

 

8. Select the image by using the Drag Drop functionality can be moved to a different folder

 

 

 

9. Images posted on the web in other players "Item Image" to find the Share feature to select the Screenshot AutoCut

 

 

 

 

 

10. Use OneDrive upload item images, and create links to the shared

 

SignIn OneDrive

 

SignIn Button : OneDrive SignIn

 

 

The icon appears on the bottom if image uploading is complete, the OneDrive.

 

Upload Button : Upload a OneDrive selected image.

Copy link Button : Copy to Clipboard to create a link to share the image uploaded on OneDrive.

 

 

 

Can be used to copy the link to the post on the community.

 

 

 

* Requests for Adding Facebook and email hope now.

email : kaki104@daum.net
facebook : https://www.facebook.com/kaki104 

 

블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

참고

Instantiate a System.Type from a type definition string

http://stackoverflow.com/questions/13842173/instantiate-a-system-type-from-a-type-definition-string

 

앱을 개발하기 위해 CrossPlatform이라는 라이브러리 프로젝트를 사용하는데, 이런 경우 스트링으로 인스턴스를 시켜야 하는 경우가 많이 있다. 일반적으로는

 

Type t = Type.GetType(typeName, false);

object result = null;

if(t != null) result = Activator.CreateInstance(t);

 

위의 문장으로 처리가 되지만, 이 문장이 동작하기 위한 선결 조건이 사용하는 프로젝트 내부에 해당 Type이 있어야 한다는 것이다. 만약 클래스라이브러리에서 위의 문장을 실행하면 Type을 찾을 수 없게 된다.

그런 경우 아래와 같이 하면 Type을 찾고 인스턴스 시킬 수 있다.

 

* contentTypeName은 네임스페이스까지 포함한 Type의 FullName이다.

 

                Popup popup = new Popup();

                var contentType = Application.Current.GetType().GetTypeInfo().Assembly.GetType(contentTypeName);

                if (contentType != null)
                {
                    var content = Activator.CreateInstance(contentType);
                    if (content != null && content is UIElement)
                    {
                        popup.Child = (UIElement)content;
                    }
                }

위와 같이 하면, 실행 중인 앱의 어셈블리에서 Type을 찾아서 반환한다.

 

블로그 이미지

MVP kaki104

* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

티스토리 툴바