programing

WPF 사용자 제어 상위 항목

abcjava 2023. 5. 6. 13:59
반응형

WPF 사용자 제어 상위 항목

사용자 컨트롤을 사용하여 로드할 수 있습니다.MainWindow런타임에윈도우의 핸들을 잡을 수 없습니다.UserControl.

난 시도했다.this.Parent하지만 항상 null입니다.WPF의 사용자 컨트롤에서 포함된 창으로 핸들을 가져오는 방법을 아는 사람이 있습니까?

컨트롤이 로드되는 방법은 다음과 같습니다.

private void XMLLogViewer_MenuItem_Click(object sender, RoutedEventArgs e)
{
    MenuItem application = sender as MenuItem;
    string parameter = application.CommandParameter as string;
    string controlName = parameter;
    if (uxPanel.Children.Count == 0)
    {
        System.Runtime.Remoting.ObjectHandle instance = Activator.CreateInstance(Assembly.GetExecutingAssembly().FullName, controlName);
        UserControl control = instance.Unwrap() as UserControl;
        this.LoadControl(control);
    }
}

private void LoadControl(UserControl control)
{
    if (uxPanel.Children.Count > 0)
    {
        foreach (UIElement ctrl in uxPanel.Children)
        {
            if (ctrl.GetType() != control.GetType())
            {
                this.SetControl(control);
            }
        }
    }
    else
    {
        this.SetControl(control);
    }
}

private void SetControl(UserControl control)
{
    control.Width = uxPanel.Width;
    control.Height = uxPanel.Height;
    uxPanel.Children.Add(control);
}

다음을 사용해 보십시오.

Window parentWindow = Window.GetWindow(userControlReference);

GetWindow메소드가 Visual Tree를 걷고 컨트롤을 호스팅하는 창을 찾습니다.

이 코드는 컨트롤이 로드된 후에 실행해야 합니다(Windows 생성자가 아님).GetWindow반품 방법null예: 이벤트 연결:

this.Loaded += new RoutedEventHandler(UserControl_Loaded); 

제 경험을 덧붙이겠습니다.Loaded 이벤트를 사용하면 작업을 수행할 수 있지만 OnInitialized 메서드를 재정의하는 것이 더 적합할 수 있습니다.로드는 윈도우가 처음 표시된 후에 발생합니다.초기화 시 창을 렌더링하기 전에 창에 컨트롤을 추가하는 등 변경할 수 있습니다.

Visual Tree Helper를 사용합니다.GetParent 또는 아래 재귀 함수를 사용하여 부모 창을 찾습니다.

public static Window FindParentWindow(DependencyObject child)
{
    DependencyObject parent= VisualTreeHelper.GetParent(child);

    //CHeck if this is the end of the tree
    if (parent == null) return null;

    Window parentWindow = parent as Window;
    if (parentWindow != null)
    {
        return parentWindow;
    }
    else
    {
        //use recursion until it reaches a Window
        return FindParentWindow(parent);
    }
}

창을 사용해야 했습니다.Loaded 이벤트 처리기 내의 Window(이) 메서드를 가져옵니다.즉, Ian Oakes의 답변과 Alex의 답변을 함께 사용하여 사용자 컨트롤의 부모를 구했습니다.

public MainView()
{
    InitializeComponent();

    this.Loaded += new RoutedEventHandler(MainView_Loaded);
}

void MainView_Loaded(object sender, RoutedEventArgs e)
{
    Window parentWindow = Window.GetWindow(this);

    ...
}

이 질문을 찾았지만 Visual Tree Helper가 작동하지 않거나 산발적으로 작동하지 않는 경우 알고리즘에 Logical Tree Helper를 포함해야 할 수 있습니다.

내가 사용하는 것은 다음과 같습니다.

public static T TryFindParent<T>(DependencyObject current) where T : class
{
    DependencyObject parent = VisualTreeHelper.GetParent(current);
    if( parent == null )
        parent = LogicalTreeHelper.GetParent(current);
    if( parent == null )
        return null;

    if( parent is T )
        return parent as T;
    else
        return TryFindParent<T>(parent);
}

이 접근 방식은 저에게 효과가 있었지만 질문만큼 구체적이지는 않습니다.

App.Current.MainWindow

이거 어때:

DependencyObject parent = ExVisualTreeHelper.FindVisualParent<UserControl>(this);

public static class ExVisualTreeHelper
{
    /// <summary>
    /// Finds the visual parent.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="sender">The sender.</param>
    /// <returns></returns>
    public static T FindVisualParent<T>(DependencyObject sender) where T : DependencyObject
    {
        if (sender == null)
        {
            return (null);
        }
        else if (VisualTreeHelper.GetParent(sender) is T)
        {
            return (VisualTreeHelper.GetParent(sender) as T);
        }
        else
        {
            DependencyObject parent = VisualTreeHelper.GetParent(sender);
            return (FindVisualParent<T>(parent));
        }
    } 
}

생성자에서 UserControl의 부모가 항상 null이지만 이벤트 핸들러에서 부모가 올바르게 설정되어 있습니다.제어 트리가 로드되는 방식과 관련이 있을 것 같습니다.이 문제를 해결하려면 로드된 컨트롤 이벤트에서 상위 항목을 가져올 수 있습니다.

예를 들어 이 질문을 확인하려면 WPF User Control의 DataContext가 Null입니다.

다른 방법:

var main = App.Current.MainWindow as MainWindow;

제게 효과가 있습니다.

DependencyObject GetTopLevelControl(DependencyObject control)
{
    DependencyObject tmp = control;
    DependencyObject parent = null;
    while((tmp = VisualTreeHelper.GetParent(tmp)) != null)
    {
        parent = tmp;
    }
    return parent;
}

이는 트리를 너무 높게 설정하고 전체 애플리케이션에 대한 절대적인 루트 창을 제공했기 때문에 저에게는 효과가 없었습니다.

Window parentWindow = Window.GetWindow(userControlReference);

그러나 이것은 즉시 창을 얻는 데 효과적이었습니다.

DependencyObject parent = uiElement;
int avoidInfiniteLoop = 0;
while ((parent is Window)==false)
{
    parent = VisualTreeHelper.GetParent(parent);
    avoidInfiniteLoop++;
    if (avoidInfiniteLoop == 1000)
    {
        // Something is wrong - we could not find the parent window.
        break;
    }
}
Window window = parent as Window;
window.DragMove();

창뿐만 아니라 트리 구조의 특정 부모를 가져오고 재귀 또는 하드 브레이크 루프 카운터를 사용하지 않으려면 다음을 사용할 수 있습니다.

public static T FindParent<T>(DependencyObject current)
    where T : class 
{
    var dependency = current;

    while((dependency = VisualTreeHelper.GetParent(dependency) ?? LogicalTreeHelper.GetParent(dependency)) != null
        && !(dependency is T)) { }

    return dependency as T;
}

에 이 전화를 Parent속성이 아직 초기화되지 않았습니다.로드 이벤트 핸들러 또는 응용 프로그램의 다른 부분에 추가합니다.

DependencyObject parent = ExVisualTreeHelper.FindVisualParent<UserControl>(this);
DependencyObject GetTopParent(DependencyObject current)
{
    while (VisualTreeHelper.GetParent(current) != null)
    {
        current = VisualTreeHelper.GetParent(current);
    }
    return current;
}

DependencyObject parent = GetTopParent(thisUserControl);

Window.GetWindow(userControl)합니다. (으)로 표시됩니다.InitializeComponent()메서드가 완료됨).

를 들어을 넣는 ) 즉, 사예된초경함우화기창(사용자 컨트롤: 파일에용사 xaml경우사자한용자컨의트롤삽컨을)에 표시됩니다.OnInitialized이트창null얻못것할입다지니을다(사용자 컨트롤의 벤될것니입이null것),(다입)이기 에 창이 표시되지 ). 이 경우 사용자 컨트롤이OnInitialized창이 초기화되기 전에 이벤트가 발생합니다.

이것은 또한 사용자 컨트롤이 창 이후에 초기화된 경우 사용자 컨트롤의 생성자에 이미 창을 가져올 수 있음을 의미합니다.

위의 금도금판 (나는 a를 추론할 수 있는 제네릭 함수가 필요합니다.Window의맥안서의 에서.MarkupExtension:-

public sealed class MyExtension : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider) =>
        new MyWrapper(ResolveRootObject(serviceProvider));
    object ResolveRootObject(IServiceProvider serviceProvider) => 
         GetService<IRootObjectProvider>(serviceProvider).RootObject;
}

class MyWrapper
{
    object _rootObject;

    Window OwnerWindow() => WindowFromRootObject(_rootObject);

    static Window WindowFromRootObject(object root) =>
        (root as Window) ?? VisualParent<Window>((DependencyObject)root);
    static T VisualParent<T>(DependencyObject node) where T : class
    {
        if (node == null)
            throw new InvalidOperationException("Could not locate a parent " + typeof(T).Name);
        var target = node as T;
        if (target != null)
            return target;
        return VisualParent<T>(VisualTreeHelper.GetParent(node));
    }
}

MyWrapper.Owner() 추론합니다.

  • 본근Window시각적 트리를 걸음으로써 (만약 의 맥락에서 사용된다면)UserControl)
  • (경맥사서는우용되되에락의▁a▁within▁of▁context▁it()의 맥락에서 되는 경우)Window

다른 접근 방식과 다른 전략.제 경우 VisualTreeHelper를 사용하거나 Telerik의 확장 메서드를 사용하여 지정된 유형의 부모를 찾을 수 없습니다.대신 애플리케이션을 사용하여 콘텐츠의 사용자 지정 주입을 허용하는 내 대화 뷰를 찾았습니다.현재의.창문들.

public Window GetCurrentWindowOfType<TWindowType>(){
 return Application.Current.Windows.OfType<TWindowType>().FirstOrDefault() as Window;
}

언급URL : https://stackoverflow.com/questions/302839/wpf-user-control-parent

반응형