2013-03-27 2 views
7

우리는 매우 장식 된 입력 요소를 많이 사용하는 WPF 응용 프로그램을 만듭니다. 데코 레이팅 된 요소의 간단한 예는 포커스가 없을 때 읽기 전용 TextBlock처럼 보이고 포커스를받은 후 TextBox가되는 TextBox입니다. 또한 변경된 값이 데이터베이스에 저장 될 때 추가 시각적 피드백이 제공됩니다. 문제는 이러한 요소가 많이 포함 된보기를 표시하면 (100이라고 가정) 매우 느리며 응용 프로그램이 응답하지 않는 것입니다.WPF에서 느리게 UI 요소를 만드는 방법은 무엇입니까?

우리는 모든 필수 요소 (예 : 초점이 맞지 않는 텍스트를 표시하는 TextBlock 및 통화 중 표시기의 회전 이미지)를 포함하는 UserControl으로이 데코레이터를 구현했습니다. 그런 다음 입력 요소를이 데코레이터 컨트롤의 자식으로 추가합니다. 즉 모든 추가 요소 외에도 데코레이터는 시각적 트리에 input 요소도 포함합니다. 같은 XAML에서이 보일 것이다 : 우리가 원하는 입력 요소를 장식하는

<custom:Decorator Context="{Binding ValueHelper}" > 
    <TextBox Text="{Binding ValueHelper.Text}"/> 
</custom:Decorator> 

이 그것을 쉽게, 그것은 하나의 텍스트 상자, 날짜 선택, 콤보 상자 또는 사용자 지정 요소가 될.

문제로 돌아 가기 : 100 개의 장식 된 텍스트 상자가 포함 된보기가 있고 그보기로 이동한다고 가정 해 봅니다. 무슨 일이야? 장식은 보이지 않지만이지만 장식 된 모든 요소에 시각적 피드백을 제공하기 위해 수백 개의 텍스트 블록, 사각형, 이미지 등을 만들어야하기 때문에 적어도 내 쿼드 코어 노트북은 오랫동안 정지합니다. 실제로 필요한 것은 100 개의 TextBlock뿐입니다. 화면에서 볼 수있는 것이기 때문입니다. 요소가 마우스 오버 이벤트를 받거나 다른 요소가 필요할 때만 포커스를 받으면됩니다. 또한 한 번에 하나의 요소 만 편집되므로 입력 요소 하나 (이 경우 텍스트 상자) 만 전체 응용 프로그램에 충분합니다.

그래서 모든 장식 요소 (또는 실제 입력 요소)를보기의 모든 요소에 대해 만들지 않고 동일한 장식을 얻는 가장 좋은 방법은 무엇입니까?


사용 사례 명확하게 장식 텍스트 상자의 예 :

텍스트 상자가 포커스 나 마우스 커서가없는 읽기 전용 TextBlock의 모양

그 위에 (에 현재 사용하지 않는 상태 1). 또한 요소에는 현재 값이 없기 때문에 세 개의 점 ("...")이 표시됩니다.

마우스 커서를 요소 위로 이동하면 요소를 수정할 수 있음을 나타 내기 위해 점으로 찍힌 녹색 직사각형이 TextBlock 주위에 나타납니다 (상태 2). TextBox가 읽기 전용으로 된 경우 색상은 빨간색입니다.

포커스 요소를받은 후 실제 값 (상태 3)을 수정하는 데 사용할 수있는 실제 TextBox로 바뀝니다.

텍스트 상자가 포커스를 잃은 후 값이 저장되고 값이 현재 저장 중임을 표시하기 위해 작업 표시기가 요소의 왼쪽에 나타납니다 (상태 4).

마지막으로 값이 저장되고 요소는 새로운 값 (상태 5)을 나타내는 유휴 상태로 돌아갑니다. 실제로 요소에는 유효성 검사 및 기타 특정 요구 사항과 관련된 더 많은 상태가 있지만 요소가 실제로 매우 장식되어 있다는 점을 확실히 알고 있습니다.대신 모든 UI 요소가 선행 그리는)

enter image description here

답변

4

는 만 사람은

필요

WPF는 당신이 템플릿을 조정할 수 있도록하는 DataTrigger를 사용하여 개체의 Template 수정할 수 있습니다 그리는 당신의 당신의 트리거

을 기반으로 실내 장식은 장식의 예 스타일은 다음과 같이 표시 될 수 있습니다

<Style TargetType="{x:Type ContentControl}"> 
    <!-- Default Template --> 
    <Setter Property="ContentTemplate" 
      Value="{StaticResource NoDecoratorTemplate}" /> 

    <Style.Triggers> 
     <DataTrigger Property="Text" Value=""> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource BlankTemplate}" /> 
     </DataTrigger> 
     <Trigger Property="IsMouseOver" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource MouseOverTemplate}" /> 
     </Trigger> 
     <Trigger Property="IsFocused" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource FocusedTemplate}" /> 
     </Trigger> 
     <DataTrigger Property="{Binding IsLoading}" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource LoadingTemplate}" /> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 
,

또한 WPF는 보이지 않는 항목을로드해서는 안됩니다. 데코레이터 Visibility="Collapsed"을 테스트하여로드 시간이 수정되었는지 확인해 볼 수 있습니다. 그것은 당신이 Template 경로를 가고 싶어하지 않는 경우

, 당신은 모든 개체의 Visibility이 시작하는 Collapsed로 설정되어 있는지 확인 할 수, 그들은을 표시 할 필요가있는 경우에 그들은 단지 Visible로 설정하세요.

로드 시간이 수정되지 않으면 아마도 다른 곳에서 문제가 발생한 것일 수 있습니다. 예를 들어, 데코레이터 항목 중 일부는 콘텐트 컨트롤에 따라 크기가 조정 된 것처럼 보이므로 실제로 느려지는 것은 객체를 표시하는 것이 아니라 객체의 크기를 결정하는 것입니다.

+0

감사합니다. 컨트롤 템플릿은 꾸미는 요소와 함께 갈 수있는 방법입니다. 그러나 이것은 실제 입력 요소의 문제를 해결하지 못합니다. TextBox는 가장 가벼운 요소이며 우리는 작성할 여유가없는 훨씬 더 무거운 사용자 입력 요소 (예 : 날짜 선택 도구)를 사용합니다. 이미 접힌 상태로 설정했지만 시각적 트리가 만들어지고 모든 관련 리소스가로드되어 심각한 성능 문제가 발생합니다. – user544511

+0

@ user544511 "모든 관련 리소스가로드되었습니다"라고 말하면 각 데코레이터가로드되었음을 의미합니까? 데코레이터에 대한 단일 UI 컨트롤을 사용하고 템플릿을 교체하는 경우 한 번에 하나의 요소 만 시각 트리에 존재하기 때문에 해당 동작을 얻지 않아야합니다. – Rachel

+0

미안하지만 휴가 중이었고 이전에 응답 할 수 없었습니다. 즉, 데커의 자식 인 실제 입력 요소 (예 : 날짜 선택기 또는 텍스트 상자)가 만들어지고 모든 리소스 (자식 요소 포함)가로드되어 비주얼 트리에 추가됩니다 (축소 된 경우에도 해당됨). 이는 날짜 선택 도구가 예를 들어보다 훨씬 무거운 요소이기 때문에 엄청난 실적을 보입니다. TextBox. – user544511

관련 문제