c# - كيفية الحصول على أطفال حاوية WPF حسب النوع؟




wpf-controls (3)

كيف يمكنني الحصول على عناصر التحكم الفرعية من نوع ComboBox في MyContainer Grid في WPF؟

<Grid x:Name="MyContainer">                    
    <Label Content="Name"  Name="label1"  />
    <Label Content="State" Name="label2"  />
    <ComboBox Height="23" HorizontalAlignment="Left" Name="comboBox1"/>
    <ComboBox Height="23" HorizontalAlignment="Left" Name="comboBox3" />
    <ComboBox Height="23" HorizontalAlignment="Left" Name="comboBox4" />
</Grid>

هذا الخط يعطيني خطأ:

var myCombobox = this.MyContainer.Children.GetType(ComboBox);

ابحث عن الطفل الأول من نوع معين يتضمن نقطة محددة سلفًا (من الشاشة):

(param 'point' هو نتيجة استدعاء وظيفة PointToScreen (تم الإعلان عنها في نوع Visual))

private TDescendantType FindDescendant<TDescendantType>(DependencyObject parent, Point screenPoint) 
         where TDescendantType : DependencyObject
{
    int count = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < count; i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        if (child is Visual)
        {
            Point point = ((Visual)child).PointFromScreen(screenPoint);
            Rect rect = VisualTreeHelper.GetDescendantBounds((Visual)child);

            if (!rect.Contains(point))
                continue;
        }

        if (child is TDescendantType)
        {
            return (TDescendantType)child;
        }

        child = FindDescendant<TDescendantType>(child, screenPoint);
        if (child != null)
        {
            return (TDescendantType)child;
        }
    }
    return null;
}

الأطفال عبارة عن مجموعة من UIElements. لذلك تحتاج إلى التكرار أكثر من العناصر وتحديد كل عنصر سواء كان من النوع المطلوب. لحسن الحظ ، هناك بالفعل طريقة Linq لهذا بالضبط ، وهي Enumerable.OfType<T> ، والتي يمكنك الاتصال بها بسهولة باستخدام بناء جملة أسلوب الامتداد :

var comboBoxes = this.MyContainer.Children.OfType<ComboBox>();

تقوم هذه الطريقة بتصفية المجموعة استنادًا إلى نوعها وترجع ، في حالتك ، فقط عناصر النوع ComboBox .

إذا كنت ترغب فقط في تحرير ComboBox الأول (كما قد يقترح اسم متغير) ، يمكنك فقط إلحاق مكالمة FirstOrDefault() إلى الاستعلام:

var myComboBox = this.MyContainer.Children.OfType<ComboBox>().FirstOrDefault();

كل هذه الإجابات لطيفة جدًا ، ولكن إذا كنت تحاول العثور على طفل مرئي محدد من النوع T ، فإما أن تكون عالقًا في الحصول على كل هذه العناصر ومن ثم العثور على تلك التي تريدها ، أو إذا كنت تأمل أن يكون أول ما تحصل عليه هو واحد تريد. لقد دمجت بعض الأساليب للعثور على نهج محدد استنادًا إلى المعايير. إنه يشبه إلى حدٍ ما LINQ ، لكنني لم أرغب في محاولة التعامل مع العداد المتكرر.

استخدمه على النحو التالي:

MyContainer.FirstOrDefaultChild<Label>(l => l.Content=="State")

لقد كتبت ذلك كطريقة تمديد.

public static class DependencyObjectExtensions
{
    public static T FirstOrDefaultChild<T>(this DependencyObject parent, Func<T, bool> selector) 
        where T : DependencyObject
    {
        T foundChild;
        return FirstOrDefaultVisualChildWhere(parent, selector, out foundChild) ? foundChild : default(T);
    }

    private static bool FirstOrDefaultVisualChildWhere<T>(DependencyObject parent, Func<T, bool> selector,
        out T foundChild) where T : DependencyObject
    {
        var count = VisualTreeHelper.GetChildrenCount(parent);
        for (var i = 0; i < count; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);
            var tChild = child as T;
            if (tChild != null)
            {
                if (!selector(tChild)) continue;
                foundChild = tChild;
                return true;
            }

            if (FirstOrDefaultVisualChildWhere(child, selector, out foundChild))
            {
                return true;
            }
        }
        foundChild = default(T);
        return false;
    }






wpf-controls