2009-05-28 2 views
1

대신 Canvas을 사용하기 위해 ItemsPanelTemplate을 무시하는 ListBox에서 작업하고 있습니다. ListBoxItems은 컨버터를 사용하여 캔버스에있는 각 ListBoxItem의 모양과 위치를 정의하는 DataTemplate입니다. ListBox이 연결된 컬렉션에 항목을 추가 할 때 다른 UIElement을 캔버스에 추가 할 수 있기를 바랍니다. ListBoxItem의 변환기 외부에서이를 수행 할 수 있습니까?WPF : ItemsPanelTemplate이 캔버스 인 ListBox에 UIElement를 추가 하시겠습니까?

내 리소스 섹션은 다음과 같이이다 :

<Style TargetType="ListBox"> 
     <Setter Property="ItemsPanel"> 
      <Setter.Value> 
       <ItemsPanelTemplate> 
        <Canvas x:Key="cnvAwesome"> 

        </Canvas> 
       </ItemsPanelTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
    <Style TargetType="ListBoxItem"> 
     <Setter Property="Canvas.Left" Value="{Binding Path=Position.X}" /> 
     <Setter Property="Canvas.Top" Value="{Binding Path=Position.Y}" /> 
    </Style> 

그리고 목록 상자 :

<ListBox x:Name="lstAwesome" ItemsSource="{Binding Source={StaticResource someCollection}}"/> 

그리고 콜렉션 목록 상자에 바인딩 :

public ObservableCollection<SomeType> someCollection {get; set; } 

그래서,이 경우 ListBox lstAwesome이 바인딩 된 someCollection 컬렉션에 항목을 추가하는 메서드가 있어야합니다.

private void AddItemToDataboundCollection(SomeType someItem) 
{ 
    someCollection.Add(someItem) 
    // I'd like to add a UIElement to the canvas that the ListBox uses to layout items here. 
} 

그래서 데이터 바인딩 된 목록 상자를 통해 ItemsPanel에 사용되는 캔버스에 UIElements를 추가 할 수 있습니까? 프로그래밍 방식으로, 해당 ListBox에 바인딩 된 항목을 컬렉션에 추가 할 때?

나는 모든 의견을 크게 고맙겠습니다!

답변

2

ListBoxCanvas에 항목을 추가하는 데 필요한 모든 정보가 포함되어 있다고 생각합니다. 난 그냥 질문에 코드를 사용하여 간단한 WPF 테스트 애플 리케이션을 넣어, 그리고 그냥 효과. ItemsSource에 바인딩 된 ObservableCollectionListBox의 항목을 추가 할 때마다 WPF는 해당 개체에 대해 ListBoxItem을 만들고 ListBoxItem의 스타일을 기반으로 해당 항목을 Canvas으로 올바른 위치에 그립니다.

위 코드를 수행 할 수 없었습니까? 그렇다면 어떤 오류가 발생 했습니까? 또는 예상했던대로 작동하지 않은 오류가 있습니까?

: 질문을 다시 읽은 후, WPF 바인딩의 작동 방식에 대한 오해가 원인이라고 생각합니다. 컬렉션을 ListBoxItemsSource에 바인딩하는 경우 컬렉션에 항목을 추가하면됩니다 (컬렉션에 INotifyCollectionChanged을 구현한다고 가정하면 ObservableCollection). WPF는 해당 인터페이스에서 제공하는 이벤트를 구독하고 목록에 대한 변경 내용을 기반으로 ListBoxItems을 작성/삭제합니다.

편집 2 :이 항목이 컬렉션에 추가 될 때 라인이 자동으로 추가되도록, 이것에 대한 DataTemplate를 사용하는 것이 더 좋을 것 동안, 나는 당신의 위치를 ​​얻을 수있는 방법을 잘 모르겠어요 선이 올바른 위치에서 시작되도록 이전에 추가 된 항목.

작동 할 수있는 옵션은 Canvas을 서브 클래스 화하고 ListBox의 경우 ItemsPanelTemplate으로 설정하는 것입니다. 컨트롤에 컨트롤이 추가 될 때마다 호출되는 함수를 재정의 (override) 할 수있는 함수가 있다고 생각합니다. 이 함수에서는 이전에 추가 한 컨트롤 (사용자의 Canvas 하위 클래스에 캐시 됨)의 위치를 ​​가져온 다음 Canvas의 컨트롤에 직접 줄 컨트롤을 추가 할 수 있습니다. 이것은 Canvas에있는 컨트롤의 위치가 바뀔 수 없다고 가정합니다. 가능한 경우 객체의 PropertyChanged 이벤트를 구독하고 이에 따라 행을 업데이트해야합니다.

편집 3 : 바인딩이 요구 사항으로 인해 옵션처럼 보이지 않으므로 가장 나쁜 옵션은 직접 자식을 추가하는 것입니다. 당신은 시각적 트리를 통해 검색하여 VisualTreeHelper.GetChild()를 사용하는 것을 수행 할 수 있습니다

Canvas canvas = FindChild<Canvas>(lstAwesome, "cnvAwesome"); 

이 코드는 재귀 적으로 지정된 타입의 제어를위한 parent의 시각적 트리를 통해 검색하고 :

private T FindChild<T>(FrameworkElement parent, string name) 
    where T : FrameworkElement 
{ 
    FrameworkElement curObject = null; 
    T obj = default(T); 
    int count = VisualTreeHelper.GetChildrenCount(parent); 
    for(int i = 0; i < count; i++) 
    { 
     curObject = VisualTreeHelper.GetChild(parent, i) as FrameworkElement; 
     obj = curObject as T; 
     if(null != obj && obj.Name.Equals(name)) 
     { 
      break; 
     } 

     obj = FindChild<T>(curObject, name); 
     if(null != obj) 
     { 
      break; 
     } 
    } 

    return obj; 
} 

이처럼 사용 이름. 여기 FrameworkElement보다 DependencyObject을 사용하는 것이 더 좋지만 (VisualTreeHelper.GetChild()이 반환하는 값이므로) NameFrameworkElement에만 정의됩니다.

멋지게 보이고 싶다면 이것을 확장 방법으로 만들 수도 있습니다.

+0

안녕하세요, 앤디 감사합니다. 그리고 네, 항목도 저에게 맞습니다. 내가 묻는 것은 추가 UIElements를 캔버스에 추가 할 수있는 것입니다. * 또한 ListItems에 추가 * 할 수 있습니다. cnvAwesome에 대한 참조를 얻을 수없는 것 같습니다 (xaml 참조). –

+0

ItemsPanelTemplate을 수정하여 Canvas에 항목을 추가 할 수 있습니까? 그렇지 않으면 ListBoxItem 당 하나의 추가 컨트롤을 추가하려면 idursun의 방법을 따르고 컬렉션에 항목을 추가 할 때마다 추가 컨트롤이 자동으로 추가되도록 DataTemplate을 수정하는 것이 좋습니다. – Andy

+0

idursun의 예제를 따르고 싶습니다. 그러나 이러한 UIElements는 절차 적으로 런타임에 추가해야합니다. 특히 항목이 ListBox에 바인딩 된 컬렉션에 추가되면 ListBox에서 사용하는 ItemsPanel 핸들을 얻을 수없고 UIElements를 추가 할 수 없습니다. 나는 정말 도움을 주셔서 감사 드리며 제 문제를 더 분명하게 할 수 있는지 알려주십시오. –

1

당신은 당신의 항목이 같은 ItemTemplate 설정하여 표시하는 방법을 지정합니다

<ListBox.ItemTemplate> 
    <DataTemplate> 
     <Rectangle Width="{Binding Width}" Height="{Binding Height}" /> 
    </DataTemplate> 
</ListBox.ItemTemplate> 

당신이 원하는 경우에 당신의 ItemTemplate 다음은 ItemTemplateSelector을 설정하고 결정할 수있는 항목에 따라 변경 될 수있는 ItemTemplate을에 프로그래밍 방식으로 사용됩니다.

+0

나는이 대답이 내 질문에 대답한다고 생각하지 않는다. ListBox가 'ItemsPanel'에 대해 캔버스를 사용하는 경우 어떻게 프로그래밍 방식으로 다른 UIElements를 해당 패널에 추가 할 수 있습니까? –

+0

그런 다음 실제로 달성하고자하는 것에 대한 구체적인 예를 들어주십시오. – idursun

+0

나는 원래 게시물을 명확하게 편집했습니다. 불명확 한 점이 있으면 알려주십시오. 감사합니다! –

관련 문제