2008-10-14 2 views
14

현재 시각적 또는 논리적 자녀에게 자녀가 추가되었을 때 알림을받을 방법을 찾고 있습니다.시각적/논리적 하위가 추가/제거 될 때 알림을받습니다.

Visual :: OnVisualChildrenChanged 메서드를 알고 있지만이 함수를 상속하거나 재정의 할 수 없기 때문에 나에게 적용되지 않습니다. 나는 사건을 찾고있다.

그래서, 추가 될 때 FrameworkElement/Visual의 소유자에게 알릴 수있는 방법이 있습니까?

답변

1

컨트롤이 비주얼 트리에 추가되거나 비주얼 트리에서 제거되면 각각 FrameworkElement.LoadedFrameworkElement.Unloaded이 발생한다고 생각합니다. 그러나 그 (것)들을 가진 무엇이든을하는 것을 시도하고 있던 약간 시간, 나는 그 (것)와하기 위하여 무언가가있을 수 있었다 그래야, 나는 그들을 연속적으로 점화하는 얻을 수 없었다 (나는 종류 사건잡이를 당시에 사용하고 있었다).

+0

글쎄, 그 자체는 FrameworkElement.Loaded를 받는다. 그러나 부모는 그 자식이 실제로 생성되어 그것에 추가되었다는 것을 인식하지 못한다. – decasteljau

1

부모 필드에 대한 참조를 유지하면서 자식 필드에 추가하고 변경 후 다시 알림을 보내면 어떨까요?

1

편집 :

방금 ​​생각한 내용입니다. 시각적 트리에 나타나는 각 요소에 Loaded 핸들러를 설정할 수 있다면 아마도 다음과 같은 기술을 사용하여 구현할 수 있습니다 (이는 가능한 해결책으로 시작하는 아주 기본적인 아이디어라고 생각하십시오).

public class ElementChildrenChangedEventArgs 
{ 
    public ElementChildrenChangedEventArgs(FrameworkElement parent, FrameworkElement child) 
    { 
     Parent = parent; 
     Child = child; 
    } 

    public FrameworkElement Parent { get; private set;} 
    public FrameworkElement Child { get; private set;} 
} 

public delegate void ChildrenChanged(ElementChildrenChangedEventArgs args); 

public static class ElementLoadedManager 
{ 
    private static readonly HashSet<FrameworkElement> elements = new HashSet<FrameworkElement>(); 

    public static void Process_Loaded(FrameworkElement fe) 
    { 
     FrameworkElement feParent = VisualTreeHelper.GetParent(fe) as FrameworkElement; 

     if (feParent != null) 
     { 
      if (elements.Contains(feParent)) 
      { 
       InvokeChildrenChanged(feParent, fe); 
      } 
     } 

     if (!elements.Contains(fe)) 
     { 
      elements.Add(fe); 
     } 

     fe.Unloaded += Element_Unloaded;   
    } 

    static void Element_Unloaded(object sender, RoutedEventArgs e) 
    { 
     FrameworkElement fe = sender as FrameworkElement; 
     elements.Remove(fe); 
     ClearUnloaded(fe); 
    } 

    static void ClearUnloaded(FrameworkElement fe) 
    { 
     fe.Unloaded -= Element_Unloaded; 
    } 

    public static event ChildrenChanged ChildrenChanged; 

    private static void InvokeChildrenChanged(FrameworkElement parent, FrameworkElement child) 
    { 
     ElementChildrenChangedEventArgs args = new ElementChildrenChangedEventArgs(parent, child); 

     ChildrenChanged changed = ChildrenChanged; 

     if (changed != null) changed(args); 
    } 
} 

아이디어 및 요구 사항은 각 요소의 Loaded 처리기에서 Process_Loaded (FrameworkElement) 메서드를 호출하는 것으로, 일부 스타일/서식 파일 설정으로 수행 할 수 있습니다.

Loaded는 라우트 된 이벤트이므로 상위 창에서만 핸들러를 설정하고 e.OriginalSource를 확인할 수 있습니다.

+0

수정 된 답변입니다. –

+0

MSDN에 따르면 Loaded 이벤트의 라우팅 전략은 거품이 발생하지 않으며 "직접"입니다. 이러한 이유로, 귀하의 솔루션 (위)이 작동하는지 여부에 대한 귀하의 의견을 읽으 려합니다. – Mark

2

은 쉽게 통지를 할

System.Windows.Controls.UIElementCollection 

을 확장하고

protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent) 

사용하지입니까?

1

자식 요소에서 연결된 이벤트를 발생시키기 위해 자식 요소에 연결된 동작을 사용할 수 있습니다. 또는 자식로드 이벤트에서 단순히 부모를 논리 트리 위로 검색하고 거기에서 메서드를 호출하거나 자식이 있음을 알리기 위해 (예 : 자식 수를 늘리는 것과 같은) 속성을 설정할 수 있습니다. 당신이 부모에게 일어날 일에 따라. 접근 설정 속성을 사용하는 경우 Unloaded도 처리해야합니다.

로드 및 언로드가 항상 예상대로 수행되지는 않습니다. 그러나 DataTemplates를 사용하여 자식 컨트롤을 만드는 경우에는 컨트롤이 만들어지고 소멸 될 때 항상 해고되어야합니다.

관련 문제