Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fade out everything "around" a given control?

In my application, I need some modal behavior in certain situations, i.e. the user should only be allowed to interact with a specific element of the UI (e.g. all controls inside a group box). I do not want to use modal dialogs, so I try to find a way to "fade out" everything except the control that should stay active, preferably by darkening everything else (thereby giving visual focus to the control in question).

How could such a behavior be achieved? Please note that the element that should become modal is at all times part of the UI, so I can't just place it on an overlay or something similar.

I've stumbled upon Decorators and Adorners, but there is rather little information on these...

like image 499
Senfsäcker Asenhorst Avatar asked May 02 '11 19:05

Senfsäcker Asenhorst


People also ask

What is a fade-out effect?

The Fade In/Fade Out behavior lets you dissolve into and out of any object by ramping the opacity of the object from 0 percent to 100 percent at the start, and then back to 0 percent at the end. You can eliminate the fade-in or fade-out effect by setting the duration of the Fade In Time or Fade Out Time to 0 frames.

How do you do fading effects?

Double click on the video footage in the timeline, and then go to the Animation tab. Move the playhead in the timeline and then click the Add button accordingly, and then adjust the Opacity slider to make a fade effect.

How do you control fade-in Audacity?

Select the part of your track that you wish to fade then select Effect from the main menu, then Amplify. In the dialog that opens move the Amplification slider down (left) to about -10dB. Then either preview and adjust or hit ok.

What is fade-out in editing?

Fade In/Out A fade is when the scene gradually turns to a single color — usually black or white — or when a scene gradually appears on screen. Fade-ins occur at the beginning of a film or scene, while fade-outs are at the end.


1 Answers

You could apply an overlay to the whole window, and set the OpacityMask of this overlay so that it is transparent above the element that must be modal. I'll try to post an example in a few minutes.


EDIT: OK, it's a bit harder than I expected... Here's a somewhat-working-but-ugly solution:

    private Grid _modalOverlay;

    private void btnShowOverlay_Click(object sender, RoutedEventArgs e)
    {
        if (_modalOverlay != null)
            root.Children.Remove(_modalOverlay);
        _modalOverlay = MakeModalOverlay(groupBox1, root, 0.5);
        root.Children.Add(_modalOverlay);
    }

    private static Grid MakeModalOverlay(FrameworkElement element, FrameworkElement root, double opacity)
    {
        var offset = GetRelativeOffset(element, root);

        Grid g = new Grid();

        var c0 = new ColumnDefinition();
        c0.Width = new GridLength(offset.X);
        var c1 = new ColumnDefinition();
        c1.Width = new GridLength(element.ActualWidth);
        var c2 = new ColumnDefinition();
        c2.Width = new GridLength(root.ActualWidth - element.ActualWidth - offset.X);

        var r0 = new RowDefinition();
        r0.Height = new GridLength(offset.Y);
        var r1 = new RowDefinition();
        r1.Height = new GridLength(element.ActualHeight);
        var r2 = new RowDefinition();
        r2.Height = new GridLength(root.ActualHeight - element.ActualHeight - offset.Y);

        g.ColumnDefinitions.Add(c0);
        g.ColumnDefinitions.Add(c1);
        g.ColumnDefinitions.Add(c2);
        g.RowDefinitions.Add(r0);
        g.RowDefinitions.Add(r1);
        g.RowDefinitions.Add(r2);

        Brush b = new SolidColorBrush(Colors.Black) { Opacity = opacity };
        for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
        {
            if (i == 1 && j == 1)
                continue;

            Rectangle r = new Rectangle();
            r.Fill = b;
            Grid.SetColumn(r, i);
            Grid.SetRow(r, j);
            g.Children.Add(r);
        }

        Panel.SetZIndex(g, int.MaxValue);

        return g;
    }

    private static Vector GetRelativeOffset(Visual visual, Visual ancestor)
    {
        Visual tmp = visual;
        Vector offset = default(Vector);
        while (tmp != ancestor)
        {
            offset += VisualTreeHelper.GetOffset(tmp);

            tmp = (Visual) VisualTreeHelper.GetParent(tmp);
            if (tmp == null)
                throw new ArgumentException("ancestor is not an visual ancestor of visual");
        }
        return offset;
    }

    private void btnHideOverlay_Click(object sender, RoutedEventArgs e)
    {
        if (_modalOverlay != null)
            root.Children.Remove(_modalOverlay);
    }

In the code above, root is the root panel of the window.

This solution kind of works, but it has two major issues:

  • It doesn't support resizing; this could probably be tackled by binding the column width and row height of the overlay grid, using converters, but it's not very straightforward
  • It prevents you from clicking other controls, but you can still interact with them using the keyboard. I think the only way to prevent this would be to actually disable them...
like image 106
Thomas Levesque Avatar answered Nov 03 '22 22:11

Thomas Levesque