I'm writing an application. I'd like to have a tutorial mode where the screen of the application darkens and single features of the application are allowed to shine through. On my actual app, I have many datagrids and listboxes so I thought the easiest way to accomplish this might be to overlay the entire screen with a semi-transparent Panel and then somehow use the opacity mask to see through the mask in certain areas to highlight them in my application while the tutorial explains what they do. The only problem is, I can't get the opacity mask to work with a visualbrush and picking out specific objects like a Listbox. Below is an example program I wrote to demonstrate simply what I am trying to do.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Two different text listboxes"/>
<ListBox Grid.Row="1" Name="myListBox1" Grid.Column="0" VerticalAlignment="Top">
<ListBoxItem Content="Item 1" Margin="3" Background="Tan"/>
<ListBoxItem Content="Item 2" Margin="3" Background="Aqua"/>
<ListBoxItem Content="Item 3" Margin="3" Background="Gold"/>
</ListBox>
<ListBox Grid.Row="1" Name="myListBox2" Grid.Column="1" VerticalAlignment="Top">
<ListBoxItem Content="Item A" Margin="3" Background="Magenta"/>
<ListBoxItem Content="Item B" Margin="3" Background="Chartreuse"/>
<ListBoxItem Content="Item C" Margin="3" Background="Chocolate"/>
<ListBoxItem Content="Item D" Margin="3" Background="Pink"/>
</ListBox>
<Button Grid.Row="2" Height="40" Margin="5" Content="Click me" Grid.ColumnSpan="2"/>
<DockPanel Grid.RowSpan="3" Background="#55000000" Grid.ColumnSpan="2">
<DockPanel.OpacityMask>
<VisualBrush Visual="{Binding ElementName=myListBox1}"/>
</DockPanel.OpacityMask>
</DockPanel>
</Grid>
Can anyone give me any tips on how to simply accomplish this mask?
So here's an example of how I've done this in the past. I was going to go the extra step and throw together a Storyboard animation to sequence through the property change of Clip
on the one object to show you how it can work in your tutorial scenario (which it did quite nicely on the last project I did this on.) except it's Friday and I'm running late leaving the office already. :)
PS: Forgot to mention that originally I just put named rectangles collapsed over top of each of the controls I wanted to show off with a -5 margin. Once their visibility was toggled to visible and they gave back Rectangle.RenderedGeometry you can grab the Rect
with a binding for your geometry with just xaml.
Or... If you don't need it dynamic, and you don't mind x layers over your outermost parent. You could always load it up in Blend -> Put Rectangle on top most z-index so it covers everything with an opacity, draw a Rectangle over your highlight area -> Select both -> [From top file menu] Select Object -> Select Path -> Select "Make Compound Path" and, voila you have a shape you can just toggle visibility on and cycle each through a storyboard.
Let me know if you have any questions or if you want me to show you to utilize the concept more, you can manually change Box1, Box2, Box3, etc on the StaticResource
on "PresenterForeground" to see the concept in action though.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="350">
<Window.Resources>
<!-- These guys are for example, you could change the StaticResource on the Clip of the Rectangle
below to reflect the changes here with a property change in a storyboard, or from a trigger, whatever -->
<Geometry x:Key="Box1">M0,0 L280,0 L280,280 L0,280 z M10,10 L130,10 L130,130 L10,130 z</Geometry>
<Geometry x:Key="Box2">M0,0 L280,0 L280,280 L0,280 z M150,10 L270,10 L270,130 L150,130 z</Geometry>
<Geometry x:Key="Box3">M0,0 L280,0 L280,280 L0,280 z M10,150 L130,150 L130,270 L10,270 z</Geometry>
<Geometry x:Key="Box4">M0,0 L280,0 L280,280 L0,280 z M150,150 L270,150 L270,270 L150,270 z</Geometry>
</Window.Resources>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="Rectangle">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="100"/>
<Setter Property="Margin" Value="20"/>
</Style>
</Grid.Resources>
<Rectangle Fill="Red"/>
<Rectangle Grid.Column="1" Fill="Blue"/>
<Rectangle Grid.Row="1" Fill="Green"/>
<Rectangle Grid.Row="1" Grid.Column="1" Fill="Orange"/>
<!-- This guy is our main foreground to cut visibility to everything else -->
<Rectangle Name="PresenterForeground" Grid.ColumnSpan="2" Grid.RowSpan="2"
Fill="#77000000"
Height="Auto"
Width="Auto"
Margin="0"
Clip="{StaticResource Box1}"/>
</Grid>
</Window>
Hope this helps and have a great weekend, cheers!