0

I am encountering an issue in my project and i don't have much more time to do research.

The goal of this project is to allow attending to tests without being physically present.

You receive a file containing your tests, you attend to them (time limited) and send back the file containing your answers.

I got a TextBox in a StackPanel, itself contained in another StackPanel.

All the controls are created programatically.

The controls are added correctly but the TextBox don't react to mouse input.... (in fact only when the textbox is the ast item and even ther only the little last pixel)

UserControl XAML file :

<UserControl x:Class="DataLibrary.View.Questions.ListQuestionInterface"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:localization ="clr-namespace:DataLibrary.Resources"
             xmlns:convert ="clr-namespace:DataLibrary.View.Converters"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             Loaded="ListQuestionInterface_OnLoaded">
    <UserControl.Resources>
        <localization:LocalizedStrings x:Key="LocalizedStrings"/>
        <convert:getVisible x:Key="getVisible"/>
        <convert:getText x:Key="getText"/>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="10*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" x:Name="body" Grid.Row="0" FocusManager.IsFocusScope="True"/>
        <Label Grid.Row="0" Margin="0,10,0,0" x:Name="explanations"/>
        <Button Content="{Binding  Path=type, Converter={StaticResource getText}}"
                HorizontalAlignment="Right" 
                Margin="0,0,10,10" 
                VerticalAlignment="Bottom" 
                Grid.Row="1" 
                Width="120" 
                Height="20" 
                Click="DisplayAnswerButton_Click"
                Visibility="{Binding Path=type, Converter={StaticResource getVisible}}"/>
    </Grid>
</UserControl>

Code Behind:

    public partial class ListQuestionInterface : UserControl
    {
        private UIElement _firstElement;
        ListQuestion q;
        private bool isTest;

        public questionType type
        {
            get
            {
                return q.Type;
            }
            set
            {
                Console.WriteLine("Attempted to write questionType");
            }
        }

        public ListQuestionInterface(ListQuestion question, bool isTest = true)
        {
            InitializeComponent();
            this.explanations.Content = question.Explanation;
            this.DataContext = this;
            this.q = question;
            this.isTest = isTest;
            refreshStackPanel();
        }

        private void refreshStackPanel()
        {
            bool first = true;
            this.body.Children.Clear();
            var enumerators = new Hashtable();
            foreach (Question subQuestion in this.q.SubQuestions)
            {
                enumerators.Add(subQuestion, subQuestion.interfaceEnumerator(isTest).GetEnumerator());
                ((IEnumerator)enumerators[subQuestion]).MoveNext();
            }
            //If the Alignemnt property has a value we'll want each pair of control to be aligned wit heach other
            //if not, we just want them stacked to the left
            if (q.Alignment.HasValue)
            {
                int maxCount = this.q.SubQuestions.Max(x => x.interfaceEnumerator(isTest).Count());
                for (int i = 0; i < maxCount; i++)
                {
                    var stack = new StackPanel
                    {
                        VerticalAlignment = VerticalAlignment.Stretch,
                        HorizontalAlignment = HorizontalAlignment.Center
                    };
                    foreach (Question subQuestion in this.q.SubQuestions)
                    {
                        try
                        {
                            var enumerator = (IEnumerator)enumerators[subQuestion];
                            var control = enumerator.Current as Control;
                            ((Panel)VisualTreeHelper.GetParent(control)).Children.Remove(control);
                            control.HorizontalAlignment = q.Alignment.Value;
                            Canvas canvas = null;
                            if (control.GetType() == typeof(Button) || control.GetType() == typeof(MaskedTextBox))
                            {
                                canvas = new Canvas();
                                if (control.GetType() == typeof(MaskedTextBox))
                                {
                                    var thick = control.Margin;
                                    thick.Left -= 5;
                                    control.Margin = thick;
                                }
                                if (first)
                                {
                                    this._firstElement = control;
                                    first = false;
                                }
                                control.Focusable = true;
                                canvas.Children.Add(control);

                            }

                            if (canvas == null)
                            {
                                stack.Children.Add(control);
                            }
                            else
                            {
                                stack.Children.Add(canvas);
                            }
                            enumerator.MoveNext();

                        }
                        catch
                        {
                            var blank = new Label
                            {
                                Content = "BLANK",
                                Visibility = Visibility.Hidden
                            };
                            stack.Children.Add(blank);
                            Console.WriteLine("No more items to display");
                        }
                    }
                    this.body.Children.Add(stack);
                }
            }
            else
            {
                var stack = new StackPanel
                {
                    VerticalAlignment = VerticalAlignment.Stretch,
                    HorizontalAlignment = HorizontalAlignment.Center,
                };
                foreach (var subQuestion in q.SubQuestions)
                {
                    var subStack = new StackPanel
                    {
                        VerticalAlignment = VerticalAlignment.Stretch,
                        HorizontalAlignment = HorizontalAlignment.Left,
                        Orientation = Orientation.Horizontal
                    };

                    var enumerator = subQuestion.interfaceEnumerator(isTest).GetEnumerator();

                    while (enumerator.MoveNext())
                    {
                        var control = enumerator.Current as Control;
                        control.HorizontalAlignment = HorizontalAlignment.Left;
                        if (control.GetType() == typeof(Button) || control.GetType() == typeof(MaskedTextBox))
                        {
                            if (first)
                            {
                                this._firstElement = control;
                                first = false;
                            }
                            control.Focusable = true;
                        }
                        ((Panel)VisualTreeHelper.GetParent(control)).Children.Remove(control);
                        subStack.Children.Add(control);
                    }
                    stack.Children.Add(subStack);

                }
                this.body.Children.Add(stack);
            }
        }

        private void DisplayAnswerButton_Click(object sender, RoutedEventArgs e)
        {
            foreach (Question question in q.SubQuestions)
            {
                question.DisplayAnswers();
            }
            refreshStackPanel();
        }

        private void ListQuestionInterface_OnLoaded(object sender, RoutedEventArgs e)
        {
            this._firstElement.Focus();
        }
    }
}

I don't think the button have somethng to do with the problem so i'll leave the converters code away.

I've checked some things already :

  • IsHitTestVisible is never set to false
  • Defining one of the stackpanels as the FocusScope don't change anything
  • If i place all my controls into canvas and the canvas into the stackpanel i can freely click on my controls but their placement is completely broken.
  • The Actual Width/height of the control is sufficient to interact with them(60x20)

The problem seems to have appeared just after using the following trick to set a first focused element on other UserControls (which are not in the current VisualTree anymore)

I really do need help since i can't seem to find someone with a similar problem.

And here are two screenshots to illustrate the problem :

No response

Got it !

The black arrows shows where my i clicked before taking the screenshot (btw if you know of any software that can do a screenshot WITH the mouse i'm taking it :) )

Community
  • 1
  • 1
Irwene
  • 2,807
  • 23
  • 48
  • 1
    This is a classic example of *why* downvoters should have to indicate a reason. +1 to counteract whoever downvoted. Way to go, guys - scare the new people away. (If you want more new coworkers that have no idea what they're doing, keep downvoting new users. It's certain to achieve the desired effect in time.) – 3Dave Nov 13 '14 at 01:13
  • At the end of your refreshStackPanel() generation code, try calling this.InvalidateVisual(); this.UpdateLayout(); And tell us if it solves this problem. – Tony Nov 13 '14 at 01:24
  • Just tested, it doesn't change anything – Irwene Nov 13 '14 at 01:29
  • 1
    delete all that horrible code and use proper XAML and DataBinding. there's no such thing as "All the controls are created programatically" or "refresh stack panel" in WPF. You need an `ItemsControl`. And I didn't downvote, btw – Federico Berasategui Nov 13 '14 at 03:32
  • @HighCore Do you have a good tutorial/Starting point for DataBinding in XAML ? I think i understood how to bind single values but i still don't get the DataTemplates – Irwene Nov 13 '14 at 07:37

1 Answers1

0

Ok, my fault here -_-'

I was so tired that i didnt't see that my stackpanel was in fact really BEHIND a Label

In my code i only had 2 row definitions, in the first i put the stackpanel AND a Label (who took the entire space).

And because it was declared later, the label was above the stackpanel thus preventing any mouse interaction with it's content.

Here is the corrected XAML :

<UserControl x:Class="DataLibrary.View.Questions.ListQuestionInterface"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:localization ="clr-namespace:DataLibrary.Resources"
             xmlns:convert ="clr-namespace:DataLibrary.View.Converters"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             Loaded="ListQuestionInterface_OnLoaded">
    <UserControl.Resources>
        <localization:LocalizedStrings x:Key="LocalizedStrings"/>
        <convert:getVisible x:Key="getVisible"/>
        <convert:getText x:Key="getText"/>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="60*"/>
            <RowDefinition Height="20*"/>
            <RowDefinition Height="10*"/>
        </Grid.RowDefinitions>
        <StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" x:Name="body" Grid.Row="0" FocusManager.IsFocusScope="True"/>
        <Label Grid.Row="1" Margin="0,10,0,0" x:Name="explanations"/>
        <Button Content="{Binding  Path=type, Converter={StaticResource getText}}"
                HorizontalAlignment="Right" 
                Margin="0,0,10,10" 
                VerticalAlignment="Bottom" 
                Grid.Row="2" 
                Width="120" 
                Height="20" 
                Click="DisplayAnswerButton_Click"
                Visibility="{Binding Path=type, Converter={StaticResource getVisible}}"/>
    </Grid>
</UserControl>

So in fact, the control was really hidden behind another one -_-'

I now know that this isn't the WPF way of doing things, but i do not know yet how to DataBind to a Template properly

I'm still taking any advices on a good tutorial/starting point for binding to a DataTemplate in XAML, tho only DataBindings i could find were for binding single values to control properties

Irwene
  • 2,807
  • 23
  • 48
  • 1
    Look at MVVM, e.g. http://stackoverflow.com/questions/1405739/mvvm-tutorial-from-start-to-finish or http://www.markwithall.com/programming/2013/03/01/worlds-simplest-csharp-wpf-mvvm-example.html or http://www.c-sharpcorner.com/UploadFile/ptmujeeb/wpf-mvvm-pattern-a-simple-tutorial-for-absolute-beginners/ etc. – BCdotWEB Nov 13 '14 at 10:30
  • Thanks, i'll be sure to take a look :) – Irwene Nov 13 '14 at 10:56