How to make some part of WPF design common to multiple windows - wpf

so I'm making this Visual Basic WPF and I have a navigation bar that will be common between multiple windows and I was wondering if there is a way to make a XAML and class only for this navigation bar and then import it to other windows so I don't have to copy and paste the same code every time I create a new window.
The current code:
MainWindow.vb
Class FloorWindow
Private Sub SetAllInactive()
' This function will change all StackPanel objects
' of the navGrid to its inactive style which consists
' of opacity .1
Dim childType As String
For Each child In navGrid.Children
childType = child.GetType().ToString()
' Check if child object of navGrid is a StackPanel
If childType = "System.Windows.Controls.StackPanel" Then
child.Opacity = 0.1
End If
Next
End Sub
Private Sub LogoBtnClick(sender As Object, e As RoutedEventArgs) Handles logoBtn.Click
Trace.WriteLine("Logo Clicked")
' Go to default page
SetAllInactive()
floorStack.Opacity = 1
End Sub
Private Sub FloorBtnClick(sender As Object, e As RoutedEventArgs) Handles floorBtn.Click
Trace.WriteLine("Floor Clicked")
' Go to floor page and change its stack to active attributes
SetAllInactive()
floorStack.Opacity = 1
End Sub
Private Sub ClientsBtnClick(sender As Object, e As RoutedEventArgs) Handles clientsBtn.Click
Trace.WriteLine("Clients Clicked")
' Go to floor page and change its stack to active attributes
SetAllInactive()
clientsStack.Opacity = 1
End Sub
Private Sub SettingsBtnClick(sender As Object, e As RoutedEventArgs) Handles settingsBtn.Click
Trace.WriteLine("Settings Clicked")
' Go to floor page and change its stack to active attributes
SetAllInactive()
settingsStack.Opacity = 1
End Sub
End Class
MainWindow.xaml
<Window x:Class="FloorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RestaurantManager"
xmlns:fa5="http://schemas.fontawesome.com/icons/"
mc:Ignorable="d"
Title="Restaurant Floor" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="navGrid" Background=" #212121">
<Grid.RowDefinitions>
<!-- Height of item menu should be same as width of the outter column -->
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<!-- Menu Item Defenition Start -->
<Border Grid.Row="0" BorderBrush="White" BorderThickness="0 0 0 .1"/>
<Button x:Name="logoBtn" Grid.Row="0" Panel.ZIndex="10" TabIndex="10" Opacity="0"/>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="40" Foreground="#03DAC5">
E
</TextBlock>
<Border Grid.Row="1" BorderBrush="White" BorderThickness="0 0 0 .1"/>
<Button x:Name="floorBtn" Grid.Row="1" Panel.ZIndex="10" TabIndex="10" Opacity="0"/>
<StackPanel x:Name="floorStack" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
<fa5:SvgAwesome Icon="Solid_BorderAll" Width="20" Foreground="White"/>
<TextBlock Foreground="White" HorizontalAlignment="Center" Margin="0,5,0,0">Floor</TextBlock>
</StackPanel>
<Border Grid.Row="2" BorderBrush="White" BorderThickness="0 0 0 .1"/>
<Button x:Name="clientsBtn" Grid.Row="2" Panel.ZIndex="10" TabIndex="10" Opacity="0"/>
<StackPanel x:Name="clientsStack" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center" Opacity=".1">
<fa5:SvgAwesome Icon="Solid_UserFriends" Width="20" Foreground="White"/>
<TextBlock Foreground="White" HorizontalAlignment="Center" Margin="0,5,0,0">Clients</TextBlock>
</StackPanel>
<Border Grid.Row="3" BorderBrush="White" BorderThickness="0 0 0 .1"/>
<Button x:Name="settingsBtn" Grid.Row="3" Panel.ZIndex="10" TabIndex="10" Opacity="0"/>
<StackPanel x:Name="settingsStack" Grid.Row="3" VerticalAlignment="Center" HorizontalAlignment="Center" Opacity=".1">
<fa5:SvgAwesome Icon="Solid_Cogs" Width="20" Foreground="White"/>
<TextBlock Foreground="White" HorizontalAlignment="Center" Margin="0,5,0,0">Settings</TextBlock>
</StackPanel>
<!-- Menu Item Defenition End -->
</Grid>
</Grid>
</Window>

Create a new UserControl (Project->Add User Control (WPF) in Visual Studio)
Move the "navGrid" element to be reused (cut and paste) from the MainWindow to the XAML markup of the newly created UserControl.
The XAML markup of the UserControl should the look something like this:
<UserControl ...
xmlns:local="clr-namespace:RestaurantManager"
xmlns:fa5="http://schemas.fontawesome.com/icons/">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="navGrid" Background=" #212121">
<Grid.RowDefinitions>
<!-- Height of item menu should be same as width of the outter column -->
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<!-- Menu Item Defenition Start -->
<Border Grid.Row="0" BorderBrush="White" BorderThickness="0 0 0 .1"/>
<Button x:Name="logoBtn" Grid.Row="0" Panel.ZIndex="10" TabIndex="10" Opacity="0"/>
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="40" Foreground="#03DAC5">
E
</TextBlock>
<Border Grid.Row="1" BorderBrush="White" BorderThickness="0 0 0 .1"/>
<Button x:Name="floorBtn" Grid.Row="1" Panel.ZIndex="10" TabIndex="10" Opacity="0"/>
<StackPanel x:Name="floorStack" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
<fa5:SvgAwesome Icon="Solid_BorderAll" Width="20" Foreground="White"/>
<TextBlock Foreground="White" HorizontalAlignment="Center" Margin="0,5,0,0">Floor</TextBlock>
</StackPanel>
<Border Grid.Row="2" BorderBrush="White" BorderThickness="0 0 0 .1"/>
<Button x:Name="clientsBtn" Grid.Row="2" Panel.ZIndex="10" TabIndex="10" Opacity="0"/>
<StackPanel x:Name="clientsStack" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center" Opacity=".1">
<fa5:SvgAwesome Icon="Solid_UserFriends" Width="20" Foreground="White"/>
<TextBlock Foreground="White" HorizontalAlignment="Center" Margin="0,5,0,0">Clients</TextBlock>
</StackPanel>
<Border Grid.Row="3" BorderBrush="White" BorderThickness="0 0 0 .1"/>
<Button x:Name="settingsBtn" Grid.Row="3" Panel.ZIndex="10" TabIndex="10" Opacity="0"/>
<StackPanel x:Name="settingsStack" Grid.Row="3" VerticalAlignment="Center" HorizontalAlignment="Center" Opacity=".1">
<fa5:SvgAwesome Icon="Solid_Cogs" Width="20" Foreground="White"/>
<TextBlock Foreground="White" HorizontalAlignment="Center" Margin="0,5,0,0">Settings</TextBlock>
</StackPanel>
<!-- Menu Item Defenition End -->
</Grid>
</Grid>
</UserControl>
Move any code (cut and paste) that is related to the navigation elements from the code-behind of the window to the code-behind of the UserControl
Add the UserControl to any window where you want to your common navigation bar:
<Window x:Class="FloorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RestaurantManager"
xmlns:fa5="http://schemas.fontawesome.com/icons/"
mc:Ignorable="d"
Title="Restaurant Floor" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<local:UserControl1 />
...
</Grid>
</Window>

Related

How to glue 2 labels together WPF

I am working on small wpf application and I can say this is my first wpf application
from the beginning.
I have problem here because I want to glue two labels together (see image below), because when I run app on smaller or bigger monitor they will be too much away from each other, and what I Want to do is to keep them together all the time and verticaly centered, so thats reason why I created grid and why I put stack panel inside, so maybe I could apply verticalalignment = 'center' to stack panel and content would be centered or whatever?
I am not sure is this code ok, so please guys comment it, I want to improve my skills about
WPF, so be free to tell me another solutions or whatever, maybe I wrote too much code or smth?
Anyway, how could I glue up this two labes to keep them near each other all the time and to keep them also centered all the time on different size of monitors.
Thanks a lot guys,
Cheers!
MY CODE:
<Window x:Class="xTouchPOS.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" WindowStartupLocation="CenterScreen" WindowState="Maximized" WindowStyle="None">
<Grid>
<!-- Definition of my Grid which contains 2 columns and 3 rows. -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3.5*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="65"/>
<RowDefinition Height="*"/>
<RowDefinition Height="0.143*" />
</Grid.RowDefinitions>
<!-- Added this rectangle to colour header of my Grid. -->
<Rectangle Grid.ColumnSpan="3">
<Rectangle.Fill>
<SolidColorBrush Color="#0091EA"></SolidColorBrush>
</Rectangle.Fill>
</Rectangle>
<!-- Added this grid and stackpanel inside this grid to place date and time, but how to glue them together text and value -->
<Grid Grid.Column="1" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Vertical">
<Label x:Name="lblTimeText" Content="Time" Margin="0,0,0,0" FontSize="15" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" VerticalAlignment="Bottom" />
<Label x:Name="lblTime" Content="labelTime" Grid.Column="0" Margin="0" FontSize="18" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Vertical">
<Label Name="lblDateText" Content="Date" Margin="0" FontSize="15" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
<Label Name="lblDate" Content="labelaDate" Margin="0" FontSize="18" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
</StackPanel>
</Grid>
</Grid>
</Window>
CODE BEHIND:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
lblDate.Content = DateTime.Now.Date.ToString("MM/dd/yyyy");
lblTime.Content = DateTime.Now.ToString("HH:mm:ss");
}
}
If you change your Labels to TextBlocks, I think you will get what you are looking for. You will need to change the column definition.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<!-- Definition of my Grid which contains 2 columns and 3 rows. -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.75*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="65"/>
<RowDefinition Height="*"/>
<RowDefinition Height="0.143*" />
</Grid.RowDefinitions>
<!-- Added this rectangle to colour header of my Grid. -->
<Rectangle Grid.ColumnSpan="3">
<Rectangle.Fill>
<SolidColorBrush Color="#0091EA"></SolidColorBrush>
</Rectangle.Fill>
</Rectangle>
<!-- Added this grid and stackpanel inside this grid to place date and time, but how to glue them together text and value -->
<Grid Grid.Column="1" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Vertical" VerticalAlignment="Center">
<TextBlock x:Name="lblTimeText" Text="Time" Margin="0,0,0,0" FontSize="15" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" VerticalAlignment="Bottom" />
<TextBlock x:Name="lblTime" Text="labelTime" Grid.Column="0" Margin="0" FontSize="18" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Vertical" VerticalAlignment="Center">
<TextBlock Name="lblDateText" Text="Date" Margin="0" FontSize="15" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
<TextBlock Name="lblDate" Text="labelaDate" Margin="0" FontSize="18" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
</StackPanel>
</Grid>
</Grid>
</Window>
Alternative
If you want to slim down your XAML, this will give the same result. It will also lock the two stack panels to the top right. Replace your Second Grid with this block
<DockPanel Grid.Row="0" Grid.ColumnSpan="2">
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Right" DockPanel.Dock="Right" Margin="5,0">
<TextBlock Name="lblDateText" Text="Date" Margin="0" FontSize="15" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
<TextBlock Name="lblDate" Text="labelaDate" Margin="0" FontSize="18" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
</StackPanel>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Right" DockPanel.Dock="Right" Margin="5,0">
<TextBlock x:Name="lblTimeText" Text="Time" Margin="0,0,0,0" FontSize="15" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" VerticalAlignment="Bottom" />
<TextBlock x:Name="lblTime" Text="labelTime" Grid.Column="0" Margin="0" FontSize="18" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
</StackPanel>
</DockPanel>
Add other stackPanel with Orientation="Horizontal"
<StackPanel Grid.Column="0" Orientation="Horizontal" >
<StackPanel Orientation="Vertical">
<Label x:Name="lblTimeText" Content="Time" Margin="0,0,0,0" FontSize="15" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" VerticalAlignment="Bottom" />
<Label x:Name="lblTime" Content="labelTime" Grid.Column="0" Margin="0" FontSize="18" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
</StackPanel>
<StackPanel Orientation="Vertical">
<Label Name="lblDateText" Content="Date" Margin="0" FontSize="15" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
<Label Name="lblDate" Content="labelaDate" Margin="0" FontSize="18" Foreground="White" HorizontalAlignment="Left" FontFamily="Arial" />
</StackPanel>
Other solution:you can use run
<TextBlock Grid.Column="1">
<TextBlock TextWrapping="Wrap" >
<Run x:Name="lblTimeText" />
<Run x:Name="lblTime"/>
</TextBlock>
</TextBlock>

WPF negative margins are not displayed correctly

I am trying to simulate a tab control with a nice TabHeader and TabContent. The control should look something like this:
This is achieved by setting the `Margin' of the first Header - "HOME" to Margin="2 0 2 -1".
ISSUE: if I re-size the window to a certain smaller width, the header item visually clips its content. Here is the result:
I really would like to know why this is happening and how ca i avoid this.
The sample xaml to prove the problem:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="550" Width="525">
<Grid Margin="0 50">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border BorderThickness="1" BorderBrush="Black" Grid.Row="1"/>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<Border Width="50" Margin="2 0 2 -1" BorderThickness="1 1 1 0" BorderBrush="Black" Background="White">
<TextBlock Text="HOME" />
</Border>
<Border Width="150" Margin="2 -20" Height="20" BorderThickness="1 1 1 0" >
<TextBlock Text="EDIT" />
</Border>
</StackPanel>
</Grid>
When you resize the window, XAML renderer redraw any flexible (still can be resized or moved relatively). when you reach the StackPanel width limit (limited by what it contains or a fixed Width) the control is ignored at redrawing (even what it contains) and the renderer keeps redrawing other flexible controls; in your case : the first border. that's why comes suddenly on the top of the others.
Moving the margin to the StackPanel will do the trick :
<StackPanel Orientation="Horizontal" Grid.Row="0" Margin="2 0 2 -1">
<Border Width="50" BorderThickness="1 1 1 0" BorderBrush="Black" Background="White">
<TextBlock Text="HOME" />
</Border>
<Border Width="150" Height="20" BorderThickness="1 1 1 0" >
<TextBlock Text="EDIT" />
</Border>
</StackPanel>
Here is a solution with 2 columns
<Grid Margin="0,50">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="Black" Grid.Row="1" />
<StackPanel Orientation="Horizontal" Grid.Row="0">
<Border Width="50" Margin="2,0,2,-1" BorderThickness="1,1,1,0" BorderBrush="Black" Background="White">
<TextBlock Text="HOME" />
</Border>
<Border Width="50" Margin="2" Height="20" BorderThickness="1,1,1,0" >
<TextBlock Text="EDIT" />
</Border>
</StackPanel>
</Grid>
This makes the grid not get clipped by the window size.
EDIT added additional column to push the border to the edge.
Cheers,
Eric
I would theorize that this is an oddity in the layout code of StackPanel. You should be able to work around it by moving the negative margin to the StackPanel itself, as opposed to the tabs within:
<Grid Margin="0 50" UseLayoutRounding="True">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border BorderThickness="1" BorderBrush="#7FFF0000" Grid.Row="1" />
<StackPanel Orientation="Horizontal" Grid.Row="0" Margin="0,0,0,-1">
<Border Width="50" Margin="2 0 2 0" BorderThickness="1 1 1 0" BorderBrush="Lime" Background="Yellow">
<TextBlock Text="HOME" />
</Border>
<Border Width="150" Margin="2 0 2 0" Height="20" BorderBrush="Blue" BorderThickness="1 1 1 0" Background="Yellow">
<TextBlock Text="EDIT" />
</Border>
</StackPanel>
</Grid>
Note that I changed the colors to assist with visual debugging. It's a useful technique, but you'll probably want to change them back :).

WPF Change TabIndex to not follow visual appearence order

I am trying to set the tab index to follow against the order of visual appearance. Meaning the buttons that appears at the top of the window gets focused first when I specifically set it not to.
Here's how the controls are structured;
DocPanel
|
|---- DockPanel
| |----- Button
| |----- Button
| |----- Button
|
|---- Grid
|----- Canvas
|---- TabControl
|------ TextBox
|------ ComboBox
The Tab Order I want;
Canvas
TextBox
ComboBox
3 buttons
Currently order is;
3 buttons
TextBox,
ComboBox
Canvas.
I tried setting KeyboardNavigation.TabNavigation="Local" for the outer DockPanel.
Then I set TabNavigation.TabIndex and TabIndex to the number that I want but that's not working.
If controls appear visually at the top of windows, is it not possible to change the tab index to focus after the controls appearing at the bottom?
Here's my XAML:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FocusManager.FocusedElement="{Binding ElementName=pic}"
Title="Window1" Height="504" Width="929">
<DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" KeyboardNavigation.TabNavigation="Local">
<DockPanel DockPanel.Dock="Top" Height="30">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Save and Close" KeyboardNavigation.TabIndex="4" TabIndex="4"/>
<Button Content="Forward" KeyboardNavigation.TabIndex="5" TabIndex="5" />
<Button Content="Delete" KeyboardNavigation.TabIndex="6" TabIndex="6" />
</StackPanel>
</DockPanel>
<Grid DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="50"/>
<ColumnDefinition MinWidth="500"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Border BorderBrush="Aqua" BorderThickness="2" >
<Canvas x:Name="pic" Grid.Column="0" Grid.Row="0" KeyboardNavigation.TabIndex="1" KeyboardNavigation.IsTabStop="True" Focusable="True" >
<Canvas.Background>
<ImageBrush ImageSource="bookcover.jpg" Stretch="Fill"/>
</Canvas.Background>
</Canvas>
</Border>
<TabControl x:Name="tabs" Grid.Column="2" Grid.Row="0">
<TabItem Header="Fax Details" IsTabStop="False">
<StackPanel>
<TextBox Name="fdCustomerFileNumber" HorizontalAlignment="Left" Height="30" KeyboardNavigation.TabIndex="2" TabIndex="2" />
<ComboBox TabIndex="3" KeyboardNavigation.TabIndex="3" Width="165" HorizontalAlignment="Left" Height="22" VerticalAlignment="Center" Name="fdDocType" IsEditable="False" />
</StackPanel>
</TabItem>
</TabControl>
</Grid>
</DockPanel>
You can set your XAML to;
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FocusManager.FocusedElement="{Binding ElementName=pic}"
Title="Window1" Height="504" Width="929">
<DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<DockPanel DockPanel.Dock="Top" Height="30">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Save and Close" TabIndex="4"/>
<Button Content="Forward" TabIndex="5" />
<Button Content="Delete" TabIndex="6" />
</StackPanel>
</DockPanel>
<Grid DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="50"/>
<ColumnDefinition MinWidth="500"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Border BorderBrush="Aqua" BorderThickness="2" >
<Canvas x:Name="pic" Grid.Column="0" Grid.Row="0" Focusable="True" >
<Canvas.Background>
<ImageBrush ImageSource="bookcover.jpg" Stretch="Fill"/>
</Canvas.Background>
</Canvas>
</Border>
<TabControl x:Name="tabs" Grid.Column="2" Grid.Row="0">
<TabItem Header="Fax Details" IsTabStop="False">
<StackPanel>
<TextBox Name="fdCustomerFileNumber" HorizontalAlignment="Left" Height="30" TabIndex="2" />
<ComboBox TabIndex="3" Width="165" HorizontalAlignment="Left" Height="22" VerticalAlignment="Center" Name="fdDocType" IsEditable="False" />
</StackPanel>
</TabItem>
</TabControl>
</Grid>
</DockPanel>
</Window>
Then in your code behind, in the New Sub, simply set the focus to the Canvas;
pic.Focus;

WPF Modal Window Transparency

I have created a modal WPF window that looks as follows:
Here is the code for the window:
<Window x:Class="Dionysus.Core.Controls.ModalWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ModalWindow" AllowsTransparency="True" Background="Transparent" WindowStyle="None">
<Grid Name="MainGrid">
<Rectangle Fill="Gray" Opacity="0.7" />
</Grid>
The "ErrorControl" is then added as follows:
MainGrid.Children.Add(uc);
The problem is as soon as I expand the stack trace, the controls transparency also changes:
I am assuming this has something to do with the ScrollViewer that uses the incorrect transparency, ie of the Rectangle instead of the containing Window.
I have also set the Opacity of the UserControl which owns the ScrollViewer to 1 and then binded the Opacity:
<ScrollViewer Background="WhiteSmoke" Opacity="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=Opacity}">
Can anyone help me?
--
UPDATE
Here is the code for the UserControl that is inserted into the Window
<Grid x:Name="LayoutRootx" Background="WhiteSmoke">
<StackPanel VerticalAlignment="Stretch">
<TextBlock TextWrapping="Wrap" Margin="5" Text="An error has occured:" Foreground="Black" FontSize="15" FontWeight="Medium"/>
<TextBlock TextWrapping="Wrap" Margin="5,10,5,5" Text="{Binding Error}"/>
<odc:OdcExpander Header="Stack Trace" Margin="5" IsExpanded="False" Background="WhiteSmoke">
<TextBox Text="{Binding StackTrace}" TextWrapping="Wrap" Margin="5,10,5,5" IsReadOnly="True" MaxHeight="370"/>
</odc:OdcExpander>
<odc:OdcExpander Header="Comment" Margin="5" IsExpanded="False">
<TextBox Text="{Binding Comment}" TextWrapping="Wrap" Margin="5,10,5,5" MaxHeight="370" Name="txtComment"/>
</odc:OdcExpander>
<StackPanel Margin="5,10,5,5" Orientation="Horizontal" HorizontalAlignment="Left">
<Button Style="{StaticResource DionysusButton}" Width="100" Height="23" IsDefault="True" Name="btnSendError">
<StackPanel Orientation="Horizontal">
<Image Source="/Dionysus.Shell;component/Images/camera-icon.png" Margin="0,0,5,0">
</Image>
<TextBlock Text="Send to IT" VerticalAlignment="Center"/>
<core:DionysusTriggerAction Height="0" Width="0" TargetControl="{Binding ElementName=btnSendError}" MethodName="SendError"></core:DionysusTriggerAction>
</StackPanel>
</Button>
<Button Style="{StaticResource DionysusButton}" Width="100" Height="23" Name="btnExit" Margin="10,0,0,0" IsCancel="True">
<StackPanel Orientation="Horizontal">
<Image Source="/Dionysus.Shell;component/Images/DeleteRed.png" Margin="0,0,5,0">
</Image>
<TextBlock Text="Close" VerticalAlignment="Center"/>
</StackPanel>
</Button>
<core:DionysusTriggerAction Height="0" Name="triggerAction2" Width="0" TargetControl="{Binding ElementName=btnExit}" MethodName="Exit"></core:DionysusTriggerAction>
</StackPanel>
</StackPanel>
</Grid>
If your window has a fixed size and cannot be resized, you can use the following trick:
<Grid>
<Border BorderThickness="100" BorderBrush="Gray" Opacity="0.7">
<Grid Background="White" Grid.Column="1" Grid.Row="1" x:Name="contentPlaceHolder">
<TextBlock Text="HELLO WORLD" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
</Grid>
However, it is unlikely that your Window will always have the same size, so to make it more dynamic, you could change the layout of the Window as follows:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="YourDesiredSize"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="YourDesiredSize"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Rectangle Fill="Gray" Opacity="0.7" Grid.Row="0" Grid.ColumnSpan="3"/>
<Rectangle Fill="Gray" Opacity="0.7" Grid.Row="2" Grid.ColumnSpan="3"/>
<Rectangle Fill="Gray" Opacity="0.7" Grid.Row="1" Grid.Column="0"/>
<Rectangle Fill="Gray" Opacity="0.7" Grid.Row="1" Grid.Column="2"/>
<Grid Grid.Column="1" Grid.Row="1" Background="White" x:Name="contentPlaceHolder">
<TextBlock Text="HELLO WORLD" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
The result of this window placed on top of another looks more or less like this:
and then instead of adding to the MainGrid, add the UserControl to the contentPlaceHolder or however you want to call it:
contentPlaceHolder.Children.Add(uc);
Okay so I found a solution that works for me, I'm sure it's not the best but it might help someone having the same problem as I did.
The problem was that controls within my UserControl that I added to my Window were transparent, although I could not figure out the reason, I found a simple workaround.
By changing the OpacityMask property of the UserControl to whatever the required Background colour is, even if the controls opacity changes, it will be masked with the Brush that you supply.
uc.OpacityMask = Brushes.WhiteSmoke;
Hope it helps someone!

Gridsplitter behaviour when hiding a WPF grid column

I'm pretty new to WPF, so please excuse me if this is 'old hat' these days... have trawled the web/forum and haven't quite found the answer I need:
I have a WPF grid with 5 columns - three for data, two for gridsplitters, which (thanks to info on this site!) seems to work and resize fine. However - I need to be able to show/hide the middle column. I can sort-of do this, but when I hide the middle column, the left hand gridsplitter still affects the "hidden" column - I need to effectively toggle between 2 & three colums. Here's my (prototype) code:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Name="Col0" Width="*" />
<ColumnDefinition Name="Col1" Width="auto" />
<ColumnDefinition Name="Col2" Width="*" />
<ColumnDefinition Name="Col3" Width="auto" />
<ColumnDefinition Name="Col4" Width="auto" />
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" Height="100" HorizontalAlignment="Center" Margin="0" Name="GridSplitter1" VerticalAlignment="Stretch" Width="3" />
<GridSplitter Grid.Column="3" Height="100" HorizontalAlignment="Center" Margin="0" Name="GridSplitter2" VerticalAlignment="Stretch" Width="3" />
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="0" HorizontalAlignment="Stretch" Margin="0" Name="Border1" VerticalAlignment="Stretch" Background="#FFC84797" />
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="2" HorizontalAlignment="Stretch" Margin="0" Name="Border2" VerticalAlignment="Stretch" Background="Black" />
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="4" HorizontalAlignment="Stretch" Margin="0" Name="Border3" VerticalAlignment="Stretch" Background="#FFA60000">
<Button Content="hide" Height="33" Name="butHide" Width="85" />
</Border>
</Grid>
Private Sub butHide_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles butHide.Click
If butHide.Content = "hide" Then
butHide.Content = "show"
Col2.Width = New GridLength(0)
Border2.Visibility = System.Windows.Visibility.Collapsed
GridSplitter2.Visibility = System.Windows.Visibility.Collapsed
Else()
butHide.Content = "hide"
Col2.Width = New GridLength(1, GridUnitType.Star)
Border2.Visibility = System.Windows.Visibility.Visible
GridSplitter2.Visibility = System.Windows.Visibility.Visible
End If
End Sub
Probably the easiest thing for you here is just to set Grid.ZIndex="2" for Border1 and then toggle the ColumnSpan between 1 and 3 in the click event.
<Border Grid.Column="0"
Grid.ZIndex="2"
Name="Border1"
.../>
Code behind
private void butHide_Click(object sender, RoutedEventArgs e)
{
if (butHide.Content.ToString() == "hide")
{
butHide.Content = "show";
Grid.SetColumnSpan(Border1, 3);
}
else
{
butHide.Content = "hide";
Grid.SetColumnSpan(Border1, 1);
}
}
The other solution is put the grid splitter in the same column you want to resize behind its content and set margin to the content. See this link for reference solution: http://www.ehow.com/how_4546867_use-gridsplitter-wpf.html
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" Width="4" Background="Yellow"/>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0 0 4 0" Background="LightGray">Text Block</TextBlock>
<TextBlock Grid.Row="0" Grid.Column="1" Background="LightGreen">Text Block 2</TextBlock>
</Grid>
Read more: How to Use a Gridsplitter in WPF | eHow.com http://www.ehow.com/how_4546867_use-gridsplitter-wpf.html#ixzz1mXqi6sGa

Resources