Search code examples
c#wpfbindingconvertersdatatrigger

How to create converter to work like "FindAncestor" for checking IsTypeFound?


I want to create a converter in which I will pass a type to find, in element's parent hierarchy & it should return true if such a type found, otherwise false.

So far, I tried below given code & it is working. but now only i have issue is it finds element parent hierarchy until element's parent is null. I want to give ancestor level for finding element in parent hierarchy. So How can I give Ancestor Level to converter??

I used LayoutHelper.cs Class to find element in parent hierarchy as given below.

public class LayoutHelper
{
    public static FrameworkElement FindElement(FrameworkElement treeRoot, Type type, int AncestorLevel)
    {
        FrameworkElement parentElement = VisualTreeHelper.GetParent(treeRoot) as FrameworkElement;
        int level = 1;
        while (parentElement != null && level <= AncestorLevel)
        {
            if (parentElement.GetType() == type)
                return parentElement;
            else
                parentElement = VisualTreeHelper.GetParent(parentElement) as FrameworkElement;
            level++;
        }
        return null;
    }
}

IsTypeFoundConverter.cs :-

public class IsTypeFoundConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        FrameworkElement element = value as FrameworkElement;
        Type type = parameter as Type;
        if (element != null && type != null)
        {
            element = LayoutHelper.FindElement(element, type,5);
            if (element != null)
                return true;
        }
        return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

DataTrigger with IsTypeFoundConverter :

 <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self} ,Converter={StaticResource isTypeFoundConverter}, ConverterParameter={x:Type Type_To_Find}}" Value="false">
        <!--Setters-->
  </DataTrigger>

Here, In data trigger how can I pass AncestorLevel to converter so I can only find element upto that level??

Thanks, Amol bavannavar


Solution

  • Declare a type to contain converter parameters:

    public sealed class MyConverterParameter
    {
        public Type AncestorType { get; set; }
        public int AncestorLevel { get; set; }
    }
    

    Re-write converter to use this type:

    public sealed class MyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var myParameter = (MyConverterParameter)parameter;
    
            // other converter stuff here
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var myParameter = (MyConverterParameter)parameter;
    
            // other converter stuff here
        }
    }
    

    Declare additional resource in XAML, e.g.:

            <DataTemplate>
                <DataTemplate.Resources>
                    <local:MyConverter x:Key="MyConverterKey"/>
                    <local:MyConverterParameter x:Key="MyConverterParameterKey" AncestorType="{x:Type Type-To-Find}" AncestorLevel="1"/>
                </DataTemplate.Resources>
    
                <!-- DataTemplate tree -->
    
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding Path-To-Bind-To, Converter={StaticResource MyConverterKey}, ConverterParameter={StaticResource MyConverterParameterKey}}" Value="Value-To-Fire-Trigger">
                        <!-- Setters -->
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
    

    P.S. Why FindAncestor mode for RealtiveSource doesn't suits you?