ডাব্লুপিএফ ব্যবহারকারী নিয়ন্ত্রণ পিতা


183

আমার একটি ব্যবহারকারীর নিয়ন্ত্রণ রয়েছে যা আমি MainWindowরানটাইমের সময় লোড করি । আমি থেকে উইন্ডোটি সহ একটি হ্যান্ডেল পেতে পারি না UserControl

আমি চেষ্টা করেছি this.Parent, তবে এটি সবসময়ই বাতিল ডাব্লুপিএফ-তে কোনও ব্যবহারকারী নিয়ন্ত্রণ থেকে কীভাবে উইন্ডোটি থাকা একটি হ্যান্ডেল পাবেন কী জানেন?

নিয়ন্ত্রণ কীভাবে লোড হয় তা এখানে:

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);
}

উত্তর:


346

নিম্নলিখিত ব্যবহার করে দেখুন:

Window parentWindow = Window.GetWindow(userControlReference);

GetWindowপদ্ধতি আপনার জন্য VisualTree পদব্রজে ভ্রমণ এবং উইন্ডো যে আপনার নিয়ন্ত্রণ হোস্ট করছেন সনাক্ত হবে।

GetWindowপদ্ধতিটি ফিরে আসতে বাধা দিতে নিয়ন্ত্রণটি লোড হওয়ার পরে (এবং উইন্ডো নির্মাণকারীতে নয়) আপনার এই কোডটি চালানো উচিত null। যেমন একটি ইভেন্ট তারের:

this.Loaded += new RoutedEventHandler(UserControl_Loaded); 

6
এখনও শূন্য ফিরে। এ যেন নিয়ন্ত্রণের কোনও পিতা-মাতা নেই।
donniefitz2

2
আমি উপরের কোডটি ব্যবহার করেছি এবং প্যারেন্ট উইন্ডোটিও আমার কাছে বাতিল হয়ে যায়।
পিটার ওয়াক

106
আমি শূন্য ফিরে আসার কারণটি খুঁজে পেয়েছি। আমি আমার ব্যবহারকারী নিয়ন্ত্রণের কনস্ট্রাক্টরে এই কোডটি রাখছিলাম। নিয়ন্ত্রণ লোড হওয়ার পরে আপনার এই কোডটি চালানো উচিত। EG একটি ইভেন্টের ওয়্যার আপ করে: এটি.লোকড + = নতুন রুটেড এভেন্টহ্যান্ডলার (ইউজারকন্ট্রোল_লয়েড);
পিটার ওয়াক

2
পলের প্রতিক্রিয়াটি পর্যালোচনা করার পরে, এটি লোডের পরিবর্তে অন-ইনটাইটেলাইজড পদ্ধতিটি ব্যবহার করা বোধগম্য হতে পারে।
পিটার ওয়াক

@ পিটারওয়ালকে আপনি আমার খুব দীর্ঘ সময়ের সমস্যা সমাধান করেছেন ... ধন্যবাদ
ওয়াকাস শাব্বির

34

আমি আমার অভিজ্ঞতা যুক্ত করব। যদিও লোড ইভেন্টটি ব্যবহার করে কাজটি করা যায়, তবে আমি মনে করি এটি অন-ইনটাইটেলাইজড পদ্ধতিটি ওভাররাইড করার জন্য আরও উপযুক্ত। উইন্ডোটি প্রথম প্রদর্শিত হওয়ার পরে লোড হয়। OnInitialized আপনাকে যেকোন পরিবর্তন করার সুযোগ দেয়, উদাহরণস্বরূপ, রেন্ডার হওয়ার আগে উইন্ডোতে নিয়ন্ত্রণ যুক্ত করুন।


8
সঠিক জন্য +1। কোন কৌশলটি ব্যবহার করতে হবে তা বোঝার সময় সময়ে সূক্ষ্ম হতে পারে, বিশেষত যখন আপনি ইভেন্টগুলি এবং ওভাররাইডগুলি মিশ্রণে ফেলে দেন (লোডড ইভেন্ট, অনলয়েড ওভাররাইড, ইনিশিয়ালড ইভেন্ট, অননিটায়ালাইজড ওভাররাইড, অ্যাসিট্যাসটেক)। এই ক্ষেত্রে, অন-ইনটাইটেলাইজড অর্থবোধ করে কারণ আপনি পিতামাতার সন্ধান করতে চান, এবং পিতামাতার "অস্তিত্ব" থাকার জন্য নিয়ন্ত্রণটি শুরু করতে হবে। লোড মানে অন্যরকম কিছু।
গ্রেগ ডি

3
Window.GetWindowএখনো ফেরৎ nullমধ্যে OnInitializedLoadedশুধুমাত্র ইভেন্টে কাজ করার জন্য মনে হচ্ছে ।
ফিজিকবুদ্ধ

ইনিশিয়াল ইভেন্টটি সংজ্ঞাযুক্ত () এর আগে সংজ্ঞায়িত করতে হবে; যাইহোক, আমার বাইন্ডেড (এক্সএএমএল) উপাদানসমূহ উত্সটি (উইন্ডো) সমাধান করতে পারেনি। সুতরাং আমি লোডড ইভেন্টটি ব্যবহার করে শেষ করেছি।
লেনোর

15

ভিজ্যুয়ালটিহেল্পার.গেটপ্যারেন্ট ব্যবহার করার চেষ্টা করুন বা প্যারেন্ট উইন্ডোটি সন্ধান করতে বেলো রিকার্সিভ ফাংশনটি ব্যবহার করুন।

 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);
        }
    }

আমি আমার ব্যবহারকারীর নিয়ন্ত্রণের মধ্যে থেকে এই কোডটি ব্যবহার করার চেষ্টা করেছি। আমি এটিকে এই পদ্ধতিতে পাস করেছি তবে এটি নালায় ফিরে গেছে, এটি নির্দেশ করে যে এটি গাছের শেষ (আপনার মন্তব্য অনুসারে)। আপনি কেন জানেন কেন? ব্যবহারকারীর নিয়ন্ত্রণের একটি পিতামাত রয়েছে যা এতে উপস্থিত ফর্ম। এই ফর্মটিতে আমি কীভাবে একটি হ্যান্ডেল পাব?
পিটার ওয়াক

2
আমি শূন্য ফিরে আসার কারণটি খুঁজে পেয়েছি। আমি আমার ব্যবহারকারী নিয়ন্ত্রণের কনস্ট্রাক্টরে এই কোডটি রাখছিলাম। নিয়ন্ত্রণ লোড হওয়ার পরে আপনার এই কোডটি চালানো উচিত। EG একটি ইভেন্টের ওয়্যার আপ করেছে: এটি.লোকড + = নতুন নতুন রাউন্ডএভেন্টহ্যান্ডলার (ইউজারকন্ট্রোল_লয়েড)
পিটার

আর একটি ইস্যু ডিবাগারে। ভিএস লোড ইভেন্টের কোডটি কার্যকর করবে, তবে এটি উইন্ডো পিতামাতাকে খুঁজে পাবে না।
বোহদান_ট্রোটসেনকো

1
আপনি যদি নিজের পদ্ধতি প্রয়োগ করতে চলেছেন তবে আপনার ভিজ্যুয়াল ট্রিহেলপার এবং লজিক্যাল ট্রিহেল্পারের সংমিশ্রণটি ব্যবহার করা উচিত। কারণ কিছু উইন্ডো নিয়ন্ত্রণের (পপআপের মতো) ভিজ্যুয়াল প্যারেন্ট নেই এবং এটি প্রদর্শিত হয় যে কোনও ডেটা টেম্পলেট থেকে উত্পাদিত নিয়ন্ত্রণগুলি লজিক্যাল পিতামাতাদের থাকে না।
ব্রায়ান রিচল

14

আমার লোড ইভেন্ট হ্যান্ডলারের মধ্যে উইন্ডো.গেট উইন্ডো (এটি) পদ্ধতিটি ব্যবহার করা দরকার। অন্য কথায়, আমি ব্যবহারকারীর নিয়ন্ত্রণের পিতামাতার জন্য অ্যালেক্সের উত্তরের সাথে মিলিয়ে আইয়ান ওকেস উভয়ই উত্তর ব্যবহার করেছি।

public MainView()
{
    InitializeComponent();

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

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

    ...
}

7

এই পদ্ধতিটি আমার পক্ষে কাজ করেছে তবে এটি আপনার প্রশ্নের মতো সুনির্দিষ্ট নয়:

App.Current.MainWindow

7

আপনি যদি এই প্রশ্নটি সন্ধান করছেন এবং ভিজ্যুয়ালটিহেল্পার আপনার জন্য কাজ করছে না বা বিক্ষিপ্তভাবে কাজ করছে না, আপনার লজিক্যাল ট্রিহেল্পারকে আপনার অ্যালগোরিদমে অন্তর্ভুক্ত করার দরকার হতে পারে।

আমি যা ব্যবহার করছি তা এখানে:

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);
}

আপনি কোডটিতে একটি পদ্ধতির নাম মিস LogicalTreeHelper.GetParentকরেছেন।
xmedeko

এটি আমার জন্য সেরা সমাধান ছিল।
জ্যাক বি নিম্বল

6

এটি সম্পর্কে:

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));
        }
    } 
}

5

আমি খুঁজে পেয়েছি যে একটি ইউজারকন্ট্রোলের পিতামাতারা কনস্ট্রাক্টরে সর্বদা শূন্য থাকে তবে কোনও ইভেন্ট হ্যান্ডলারে পিতা-মাতার সঠিকভাবে সেট করা থাকে। আমার ধারণা কন্ট্রোল ট্রিটি যেভাবে বোঝা হচ্ছে তাতে এটির কিছু করার দরকার আছে। সুতরাং এটির কাছাকাছি পেতে আপনি নিয়ন্ত্রণগুলি লোড ইভেন্টে পিতামাতাকে পেতে পারেন।

উদাহরণস্বরূপ এই প্রশ্নের চেকআউট করার জন্য ডাব্লুপিএফ ব্যবহারকারী নিয়ন্ত্রণের ডেটা কনটেক্সটটি নাল N


1
আপনার প্রথমে এটি "গাছ" এ থাকার জন্য অপেক্ষা করতে হবে। অনেক সময় খুব অসুবিধে হয়।
user7116

3

অন্য উপায়:

var main = App.Current.MainWindow as MainWindow;

আমার জন্য কাজ করেছেন, এটি নির্মাণকারীর পরিবর্তে "লোডেড" ইভেন্টে রাখতে হবে (বৈশিষ্ট্য উইন্ডোটি ডাবল ক্লিক করুন এবং এটি আপনার জন্য হ্যান্ডলার যুক্ত করবে)।
কনটাঙ্গো

(আমার ভোট আয়ানের গৃহীত উত্তরের জন্য, এটি কেবলমাত্র রেকর্ডের জন্য) এটি যখন ব্যবহারকারী নিয়ন্ত্রণে অন্য কোনও উইন্ডোতে শোডায়ালগের সাথে থাকে, তখন ব্যবহারকারী নিয়ন্ত্রণে বিষয়বস্তু সেট করে এটি কাজ করে না। অনুরূপ পন্থাটি হ'ল অ্যাপ.কন্ট্রন.উইন্ডোগুলির মধ্য দিয়ে চলতে এবং উইন্ডোটি যেখানে নিম্নলিখিত শর্তটি ব্যবহার করে (কারেন্ট.ওয়াইন্ডোস.কাউন্ট - 1) থেকে 0 (অ্যাপ্লিকেশন। বর্তমান। উইন্ডোজ [আইডিএক্স] == ব্যবহারকারীর নিয়ন্ত্রণ) সত্য । যদি আমরা এটি বিপরীত ক্রমে করি তবে এটি সম্ভবত শেষ উইন্ডো হতে পারে এবং আমরা কেবল একটি পুনরাবৃত্তি সহ সঠিক উইন্ডোটি পাই। userControlRef সাধারণত হয় এই UserControl বর্গ মধ্যে।
মিশনজয়

3

এটি আমার পক্ষে কাজ করছে:

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

3

এটি আমার পক্ষে কার্যকর হয়নি, কারণ এটি গাছের অনেক উপরে গিয়েছিল এবং পুরো অ্যাপ্লিকেশনটির জন্য নিখুঁত রুট উইন্ডো পেয়েছে:

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();

আপনার একটি স্বেচ্ছাসেবী 'এড়ানো' ইনফিনিটলুপ 'ভেরিয়েবলের পরিবর্তে নাল চেক ব্যবহার করা উচিত। প্রথমে নালটি পরীক্ষা করার জন্য আপনার 'সময়' পরিবর্তন করুন এবং যদি শূন্য না হয়, তবে এটি উইন্ডো না কিনা তা পরীক্ষা করুন। অন্যথায়, কেবল বিরতি / প্রস্থান করুন।
মার্ক এ। ডোনোহো

@ মারকুয়েলভ সাধারণত, আমি প্রতিটি লুপটিতে একটি "এড়ানো" ইনফিনিটলুপ "চেক যুক্ত করি যা কিছু ভুল হয়ে গেলে তত্ত্বগতভাবে আটকে যেতে পারে। রক্ষণাত্মক প্রোগ্রামিং এর অংশ। প্রতিটি প্রায়শই, প্রোগ্রামটি হ্যাং এড়ানোর কারণে এটি ভাল লভ্যাংশ প্রদান করে। ডিবাগিংয়ের সময় খুব দরকারী এবং যদি ওভাররন লগ থাকে তবে উত্পাদনে খুব কার্যকর। আমি এই কৌশলটি ব্যবহার করি (অন্য অনেকের মধ্যে) সুনির্দিষ্ট কোড লিখতে সক্ষম করতে যা স্রেফ কার্যকর হয়।
কনটাঙ্গো

আমি প্রতিরক্ষামূলক প্রোগ্রামিং পাই এবং আমি নীতিগতভাবে এটি সম্পর্কে একমত হই, তবে একটি কোড পর্যালোচক হিসাবে আমি মনে করি এটি আসল যুক্তি প্রবাহের অংশ নয় এমন স্বেচ্ছাচারী ডেটা প্রবর্তনের জন্য পতাকাঙ্কিত হবে। আপনার কাছে নাল পরীক্ষা করে অসীম পুনরাবৃত্তি বন্ধ করার জন্য প্রয়োজনীয় সমস্ত তথ্য ইতিমধ্যে রয়েছে কারণ অসীমভাবে কোনও গাছ পুনরুক্ত করা অসম্ভব। নিশ্চিত যে আপনি পিতামাতাকে আপডেট করতে এবং একটি অসীম লুপ রাখতে ভুলে যেতে পারেন তবে আপনি সেই অনিয়মিত পরিবর্তনশীলটিকে আপডেট করতে খুব সহজেই ভুলে যেতে পারেন। অন্য কথায়, নতুন, সম্পর্কিত সম্পর্কযুক্ত ডেটা প্রবর্তন না করে শুল্ক অনুসন্ধান করা ইতিমধ্যে রক্ষণাত্মক প্রোগ্রামিং।
মার্ক এ। ডোনোহো

1
@ মারকুইলিভ আমাকে সম্মত হতে হবে অতিরিক্ত নাল চেক যুক্ত করা ভাল প্রতিরক্ষামূলক প্রোগ্রামিং।
কনটাঙ্গো

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

দয়া করে এটি মুছুন এবং এমন কোনও বিন্দু সংহত করুন যা এটি ইতিমধ্যে আপনার অন্য উত্তরের সাথে আচ্ছাদিত হয়নি (যা আমি এটির উত্তম হিসাবে রূপান্তরিত করেছি)
রুবেন বারটেলিংক


0

উপরের সোনার ধাতুপট্টাবৃত সংস্করণ (আমার একটি জেনেরিক ফাংশন প্রয়োজন যা একটি 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)
  • উইন্ডোটি এটির মধ্যে ব্যবহৃত হয় (যদি এটি কোনও চিহ্নের প্রসঙ্গে ব্যবহৃত হয় Window)

0

বিভিন্ন পদ্ধতি এবং বিভিন্ন কৌশল আমার ক্ষেত্রে আমি ভিজুয়ালটিহেল্পার ব্যবহার করে বা প্রদত্ত প্রকারের পিতামাতার সন্ধানের জন্য টেলিরিকের কাছ থেকে এক্সটেনশন পদ্ধতিগুলি ব্যবহার করে আমার কথোপকথনের উইন্ডোটি খুঁজে পেলাম না। পরিবর্তে, আমি আমার ডায়ালগ ভিউটি পেয়েছি যা অ্যাপ্লিকেশন.কন্টেন.উইন্ডোস ব্যবহার করে সামগ্রীগুলির কাস্টম ইনজেকশন গ্রহণ করে।

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

0

Window.GetWindow(userControl)প্রকৃত জানালা পরই জানালা সক্রিয়া করা হয় ফিরে আসবে ( InitializeComponent()পদ্ধতি সমাপ্ত)।

এর অর্থ হ'ল, যদি আপনার ব্যবহারকারীর নিয়ন্ত্রণটি উইন্ডোটির সাথে একত্রে শুরু করা হয় (উদাহরণস্বরূপ আপনি উইন্ডোটির এক্সএএমএল ফাইলটিতে আপনার ব্যবহারকারী নিয়ন্ত্রণটি রেখেছেন), তবে ব্যবহারকারীর নিয়ন্ত্রণের OnInitializedইভেন্টে আপনি উইন্ডোটি পাবেন না (এটি নাল হবে), কারণ OnInitializedসেক্ষেত্রে উইন্ডোটি শুরু হওয়ার আগে ব্যবহারকারীর নিয়ন্ত্রণের ইভেন্টটি ছড়িয়ে পড়ে।

এর অর্থ হ'ল যদি আপনার ব্যবহারকারীর নিয়ন্ত্রণটি এর উইন্ডোর পরে আরম্ভ করা হয় তবে আপনি ব্যবহারকারী নিয়ন্ত্রণের কনস্ট্রাক্টরে উইন্ডোটি ইতিমধ্যে পেতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.