2017-09-29 1 views
0

내 WPF 응용 프로그램에 목록 상자가 있습니다.목록 상자의 ItemTemplate에 항목 소스 자체의 항목 포함

<ListBox ItemsSource="{Binding ButtonsCollection}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Border BorderBrush="Black" BorderThickness="2" > 
       **Here I want to insert the current button** 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

내 viewmodel에는 ButtonsCollection이라는 속성 모음이 있습니다. 다음과 같이 말합니다 : 내용이 "a"인 버튼 내용이 "b"인 버튼, 내용이 "c"인 버튼입니다.

이제 ItemTemplate에서 선언 한대로 목록 상자에 각 단추를 테두리로 표시하고 싶습니다.

+1

시도해 보셨습니까? ContentPresenter Content = "{Binding}"/> –

+0

"내 뷰 모델에는 버튼 모음이 있습니다." 이상하게 들린다. 뷰 모델에는 뷰 요소가 없어야합니다. 대신 몇 가지 속성이있는 항목 클래스가 있어야합니다. 그런 다음 ItemTemplate은 뷰 모델 항목 속성에 바인딩 된 속성이있는 Button을 선언합니다. – Clemens

답변

1

DataTemplate은 ItemsControl (사용자의 경우 ListBox)의 각 항목에 대해 인스턴스화됩니다. 그것의 유일한 역할은 렌더링 될 때 아이템이 어떻게 보이는지를 기술하는 것입니다.

DataContext 에는에 UI 상태를 설명하는 개체가 있어야합니다.

그건 별거입니다. 이 방식으로 UI와 백엔드는 여러 사람이 독립적으로 개발할 수 있으며, DataContext는 계약입니다.

물론 토마스 크리스토프은 프레임 워크가 그런 식 으로든 그렇게 할 것을 강요하지 않습니다.

이 같은 그것을 할 경우

<ListBox ItemsSource="{Binding ButtonsCollection}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Border BorderBrush="Black" BorderThickness="2" > 
       <ContentControl Content={Binding}"/> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

가 작동 할 수 있지만 곧 다른 ItemsControl에 동일한 모음을 결합으로, 가 충돌합니다. 왜? WPF의 모든 FrameworkElement에는 정확히 한 개의 부모가 있어야합니다. WPF는 "요소가 이미 다른 요소의 자식입니다."라는 예외를 throw합니다.

당신은 MVVM 패턴을 따라 클래스에서 버튼의 논리적 표현을 캡슐화하는 경우 :

public class NamedCommand : ICommand 
{ 
    private Action _action; 

    public string Name { get; private set; } 

    public NamedCommand(string name, Action action) 
    { 
     Name = name; 
     _action = action; 
    } 

    public virtual bool CanExecute(object parameter) 
    { 
     return true; 
    } 

    public void Execute(object parameter) 
    { 
     if (_action != null) 
      _action(); 
    } 

    // Call this whenever you need to update the IsEnabled of the binding target 
    public void Update() 
    { 
     if (CanExecuteChanged != null) 
      CanExecuteChanged(this, EventArgs.Empty); 
    } 

    public event EventHandler CanExecuteChanged; 
} 

당신이 여러 컨트롤, 예를 들어, 동일한 모음을 결합 할 수있다 목록 상자의 메뉴 표시 줄, 컨텍스트 메뉴, 사이드 패널 등 귀하의 경우에는

: 백그라운드 스레드를 조작하려고 할 때

<ListBox ItemsSource="{Binding Commands}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Border BorderBrush="Black" BorderThickness="2" > 
       <Button Content="{Binding Name}" Command="{Binding}"/> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

또 다른 문제는, 당신이 당신의 현재 접근 방식을 사용하여에 실행 거입니다 귀하의 버튼. UI 요소는 스레드를 생성 한 스레드 (STA 스레드)와 연결됩니다. Dispatcher.Invokes에서 모든 호출을 래핑하는 결과를 가져 오며, 어느 시점에서 교착 상태가 발생할 수 있습니다. 그러나 INotifyPropertyChanged를 구현하고 필요한 경우 PropertyChanged를 올리면 WPF 프레임 워크에이 부담이 가해집니다 (업데이트 알림은 기본 스레드에서 발송 됨).

마지막주의 사항으로 코드 숨김에서 UI를 만드는 것이 항상 나쁜 생각은 아닙니다. 애플리케이션에 플러그인 시스템을 구현하고 레이아웃에 접을 수있는 영역을 예약하여 알 수없는 플러그인의 UI를 호스팅한다고 가정 해 보겠습니다. 플러그 인 개발자가 정확히 2 개의 단추와 텍스트 상자를 갖도록 강요 할 수 없으므로 DataTemplate과 잘 맞습니다. 한 가지 좋은 해결책은 ContentControl을 예약 된 공간에 배치하고 개발자가 구현할 수있는 object GetUI(); 메서드를 포함하고 ContentControl.Content = ActivePlugin과 같은 호출을위한 인터페이스를 제공하는 것입니다.GetUI();