1

I got the following code, is going to be a dynamically generated grid:

string xaml = "<Grid Margin='8 8 0 0' Width='175'>" +
                "<Grid.RowDefinitions>" +
                    "<RowDefinition Height='115'/>" +
                    "<RowDefinition Height='*'/>" +
                    "<RowDefinition Height='Auto'/>" +
                "</Grid.RowDefinitions>" +
                "<Image Source='C:/Users/SaFteiNZz/Curro/yo2.png' Height='115' Width='171' Stretch='Uniform'/>" +
                "<Button x:Name='BtnEditAc' Grid.Row='0' Style='{StaticResource MaterialDesignFloatingActionMiniAccentButton}' HorizontalAlignment='Right' VerticalAlignment='Bottom' Margin='0,0,16,-20'>" +
                    "<materialDesign:PackIcon Kind='AccountSettingsVariant' Width='30' Height='30' Margin='0,0,0,5'/>" +
                "</Button>" +
                "<StackPanel Grid.Row='1' Margin='8,24,8,8'>" +
                    "<TextBlock TextWrapping='Wrap' FontWeight='Bold'>Pablo Antonio Hernandez Hernandez</TextBlock>" +
                    "<TextBlock TextWrapping='Wrap' VerticalAlignment='Center'>46080696N</TextBlock>" +
                "</StackPanel>" +
                "<Border BorderBrush='White' BorderThickness='1' CornerRadius='0' Grid.Row='0' Grid.RowSpan='3'>" +
                    "<Border.Effect>" +
                        "<DropShadowEffect BlurRadius='10' Direction='-90' Color='Black' ShadowDepth='0'/>" +
                    "</Border.Effect>" +
                "</Border>" +
            "</Grid>";

UIElement element = (UIElement)XamlReader.Parse(xaml, context);
empDisplay.Children.Add(element);

Like that the code works.

But I want to set a click event to the button (BtnEditAc) which if I do directly in the XAML string procs an error(Couldn't create a click from text BtnEditAc_Click or something like that).


Is there a way to set the click event for that button? or connect to a function somehow?

I'm about to make it using CLR objects coded instead of XamlReader, but first I want to know if there's a solution for this.

Hope you know what I'm doing wrong.

SaFteiNZz
  • 348
  • 4
  • 18
  • You could navigate the tree (or find button by name) and add a delegate to click event. I think that you can't do it directly from the string...where would you put the code of the event handler? – Babbillumpa Jul 05 '18 at 13:08
  • @Babbillumpa the event handler is just below the function that contains that, in the same class. – SaFteiNZz Jul 05 '18 at 13:17

2 Answers2

1

Let's see if this solution could work:

//Here you have the grid
Grid element = (Grid)XamlReader.Parse(xaml, context);
//Now try to get the button
Button btn = (Button)element.FindName("BtnEditAc");
if(btn != null)
{
    btn.Click  += new RoutedEventHandler(OnBtnEditAcClick);
}

Where OnBtnEditAcClick is the event handler. Then add the element to your main view:

empDisplay.Children.Add(element);

I hope it will help.

Babbillumpa
  • 1,854
  • 1
  • 16
  • 21
  • Nothing, take a look also at the other answer, he added the case in which you don't know the name of your control and find it navigating the visual tree. – Babbillumpa Jul 05 '18 at 13:37
0

You can parse Command binding from xml instead of Click events:

<Button x:Name='BtnEditAc' Command='{Binding MyCommand}' Grid.Row='0' ...

If for some reason you don't want to use commands, you may manually add click event in code, if only you can find the Button in the xaml element you just parsed. For example, if you know the root element in your serialized xaml will be Grid:

Grid rootElement = (Grid)XamlReader.Parse(xaml, context);
grdMain.Children.Add(rootElement);
Button btn = (Button)rootElement.FindName("BtnEditAc");
btn.Click += btn_Click;

Or:

UIElement elem = (UIElement)XamlReader.Parse(xaml, context);
Button b =(Button) LogicalTreeHelper.FindLogicalNode(elem, "BtnEditAc");

As an alternative, if you don't know the type of root element you can use this code to find it by name & type:

    public static T FindChild<T>(this DependencyObject parent, string childName)
       where T : DependencyObject
    {
        // Confirm parent and childName are valid. 
        if (parent == null) return null;

        T foundChild = null;

        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);
            // If the child is not of the request child type child
            T childType = child as T;
            if (childType == null)
            {
                // recursively drill down the tree
                foundChild = FindChild<T>(child, childName);

                // If the child is found, break so we do not overwrite the found child. 
                if (foundChild != null) break;
            }
            else if (!string.IsNullOrEmpty(childName))
            {
                var frameworkElement = child as FrameworkElement;
                // If the child's name is set for search
                if (frameworkElement != null && frameworkElement.Name == childName)
                {
                    // if the child's name is of the request name
                    foundChild = (T)child;
                    break;
                }
            }
            else
            {
                // child element found.
                foundChild = (T)child;
                break;
            }
        }

        return foundChild;
    }

or if you don't know the name of your button, you can for example get the first child of type Button (or implement a method that will return all children of a given type) with this extension method:

    public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject
    {
        if (depObj == null) return null;

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            var child = VisualTreeHelper.GetChild(depObj, i);

            var result = (child as T) ?? GetChildOfType<T>(child);
            if (result != null) return result;
        }
        return null;
    }

If you want to set your event handler in xaml and parse it manually, I don't know if it can be done.

Arie
  • 5,251
  • 2
  • 33
  • 54
  • Yes command binding was one of my alternatives, "grid.FindName()" has ended up being the shortest and easiest way in this case. Thank you for showing more alternatives and cases. – SaFteiNZz Jul 05 '18 at 13:43