/// <summary> /// When the expander expands, need to put the error message in the /// adorner layer because the controls below it, may have their own /// adorner validation error messages, this places the expander /// popup on top of all other adorder layer elements. /// </summary> void _objErrorsExpander_Expanded(object sender, RoutedEventArgs e) { //this forces the ErrorMessage to be reread from it's source this.InvalidateProperty(ErrorMessageProperty); var expanderGrid = VisualTreeSearchAssistant.FindVisualChild <Grid>(_errorsExpander); _errorsExpanderAdornerLayer = AdornerLayer.GetAdornerLayer(expanderGrid); String[] delimiter = { Environment.NewLine }; String[] errorMessages = this.ErrorMessage.Split(delimiter, StringSplitOptions.RemoveEmptyEntries); Array.Sort(errorMessages); var txt = new TextBlock { Width = this.Width, TextWrapping = TextWrapping.Wrap, Text = string.Join(Environment.NewLine + Environment.NewLine, errorMessages), Padding = new Thickness(5), Foreground = this.ErrorPopUpForeground, Background = this.ErrorPopUpBackground, Effect = new System.Windows.Media.Effects.DropShadowEffect { ShadowDepth = 2 } }; //need to move the TextBlock down below the expander and indent a little var obj = new TranslateTransform(5, _errorsExpander.ActualHeight + 2); txt.RenderTransform = obj; _textBlockAdorner = new TextBlockAdorner(expanderGrid, txt); _textBlockAdorner.MouseLeave -= _objTextBlockAdorner_MouseLeave; _textBlockAdorner.MouseEnter -= _objTextBlockAdorner_MouseEnter; _errorsExpanderAdornerLayer.Add(_textBlockAdorner); }
/// <summary> /// When the expander collapses, need to remove the TextBlock adorner /// </summary> void _objErrorsExpander_Collapsed(object sender, RoutedEventArgs e) { if (_errorsExpanderAdornerLayer != null) { _textBlockAdorner.MouseLeave -= _objTextBlockAdorner_MouseLeave; _textBlockAdorner.MouseEnter -= _objTextBlockAdorner_MouseEnter; _errorsExpanderAdornerLayer.Remove(_textBlockAdorner); _textBlockAdorner = null; _errorsExpanderAdornerLayer = null; } }