WPF how to set stackpanel as resources and reuse it in TabControls - wpf

I am new to C# and WPF so please give me some ideas:
I have an WPF app used to display some stack panels,all stack panels default Visibility is set to collapsed and they will switch to visible according to the received data.
Now I want to make all these stack panels to resources so I can reuse it in some new added tab controls and stack panels.
<StackPanel x:Name="ColorOption" Visibility="Collapsed">
<TextBlock Text="Line Color" Style="{StaticResource ItemNameTextBlockStyle}"/>
<Button Style="{StaticResource ColorButtonStyle}" Click="Color_Click">
<Button.Content>
<Rectangle x:Name="LineColorRect" Style="{StaticResource ColorSelectionRectangleStyle}" />
</Button.Content>
</Button>
</StackPanel>
Above is one example of stack panels I am using. In the code behind the function "Color_Click" will change this "ColorOption" stack panel state and do something.
However after I try to put this stack panel into Windows.Resources
<Window.Resources>
<StackPanel x:Name="ColorOption" Visibility="Collapsed" x:Key="ColorOption">
<TextBlock Text="Line Color" Style="{StaticResource ItemNameTextBlockStyle}"/>
<Button Style="{StaticResource ColorButtonStyle}" Click="Color_Click">
<Button.Content>
<Rectangle x:Name="LineColorRect" Style="{StaticResource ColorSelectionRectangleStyle}" />
</Button.Content>
</Button>
</StackPanel>
</Window.Resources> (I also put the style files inside)
In the tab controls I did
<TabControl>
<TabItem Header="Tab 1" Content="{StaticResource ColorOption}"/>
</TabControl>
The visual studio shows error in the code behind says "ColorOption does not exist in the current context"
How can I fix this? Is any way to set the context? thank you

You can simply wrap the StackPanel in ContentControl and make it ControlTemplate.
<ControlTemplate x:Key="ColorOptionTemplate" TargetType="{x:Type ContentControl}">
<StackPanel x:Name="ColorOption" Visibility="Collapsed">
<TextBlock Text="Line Color" Style="{StaticResource ItemNameTextBlockStyle}"/>
<Button Style="{StaticResource ColorButtonStyle}" Click="Color_Click">
<Button.Content>
<Rectangle x:Name="LineColorRect" Style="{StaticResource ColorSelectionRectangleStyle}"/>
</Button.Content>
</Button>
</StackPanel>
</ControlTemplate>
However, you will need to change properties of controls inside the ContentControl and it would be cumbersome. So the StackPanel could be wrapped in UserControl instead.
<UserControl x:Class="WpfApp1.ColorOptionControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel x:Name="ColorOption" Visibility="Collapsed">
<TextBlock Text="Line Color" Style="{StaticResource ItemNameTextBlockStyle}"/>
<Button Style="{StaticResource ColorButtonStyle}" Click="Color_Click">
<Button.Content>
<Rectangle x:Name="LineColorRect" Style="{StaticResource ColorSelectionRectangleStyle}"/>
</Button.Content>
</Button>
</StackPanel>
</UserControl>
This is a common way in WPF. The downside is that you will need to add dependency properties to UserControl and wire up them with dependency properties of internal controls so that you can set their values at the level of UserControl and bridge them with external controls and window. This could be complicated and cumbersome as well.
So I think ideally it would be better to find an existing control which has similar functionalities you want and create a custom control deriving from the existing one.

Related

WPF Button from Controltemplate isn't visible

I want to instantiate two Controls (an Expander and a Button) from two ControlTemplates. They are docked in a Dockpanel (right and left). The Expander is visible and it works fine, but the Button isn't visible.
The ControlTemplate of the Button in App.xaml:
...
<ControlTemplate x:Key="OpenFileButton" TargetType="{x:Type Button}">
<Image Name="OpenFileButton" Source="F:\AudioNodeGUI_XAML\images\filebutton.jpg">
</Image>
</ControlTemplate>
...
And the instantiation in a usercontrol:
<Grid>
<Image Source="F:\AudioNodeGUI_XAML\images\FileInputNode.jpg"/>
<DockPanel Name="dock" Width="151" Height="20" Margin="27,53,122,139">
<Expander Name="expander" Template="{StaticResource FileExpander}" Height="20" Width="41" PreviewMouseLeftButtonUp="expand" DockPanel.Dock="Left">
<ListView Name="usedFiles" Background="Black" BorderBrush="Transparent" BorderThickness="0" Width="140" Height="120" Opacity="0.5">
</ListView>
</Expander>
<Button Name="OpenFileButton" Template="{StaticResource OpenFileButton}" DockPanel.Dock="Right" />
</DockPanel>
</Grid>
But the Button isn't visible, neither in the Designer (just the outline) nor in execution. What am I doing wrong?
I suspect that your issue is just incorrect path to the image file. Unfortunately you won't have any tip about this kind of error neither in designer nor in output window. However if you have ReSharper it should highlight the path to the file if it doesn't exist

How To Make A WPF UserControl Act As A Container

I'm trying to create a Toolbar control that can group selected buttons with a border and a label. If there is already a built-in control that will do this then I could use that instead of building a UserControl.
If not, then what I'm wanting to build is a UserControl that would allow me to enter one-to-many of my ImageButton UserControls and set a GroupLabel text like below. Can this be done in WPF?
<User_Controls:ToolbarGroup GroupLabel="Entity">
<User_Controls:ImageButton ButtonText="Entity Setup"/>
<User_Controls:ImageButton ButtonText="New Entity"/>
</User_Controls:ToolbarGroup>
PS: I would post an image but this quirky forum won't allow me to post an image.
If i have got you correctly then I think you can achieve this way also, and on mouse eneter and leave event you can do the button click job.
for setting text you can use a grid and a label inside it to set the text, and Image buttons below it.
<UserControl x:Class="ABC.View.Oats"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Image Source="{Binding Image}" Stretch="Fill"/>
</Grid>
</UserControl>
I think what you're looking for is a GroupBox, it has a header property where you can set the label.
Something like this:
<GroupBox Width="300" Height="100">
<GroupBox.Header>
<Label>Text</Label>
</GroupBox.Header>
<StackPanel>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
</StackPanel>
</GroupBox>
I would also recommend using the groupbox, it seems to be doing exactly what you want it to do and it looks neat. Here's some examples on how to use them: http://www.dotnetperls.com/groupbox-wpf
On the other hand, if you believe the groupbox is not sufficient, you could create a control that inherits from the groupbox and you could extend it and add whatever you need to it. It would look like this:
public class customGroupBox: GroupBox{
....Add whatever you need here
}
Thanks for the replies. I tried the GroupBox and it's not the layout we want because we want the label underneath the buttons and centered. I never could find a way to add a collection to the UserControl. Maybe I didn't ask the question right by calling it a container. The code below will work, but it's not elegant. I wanted something that would wrap the layout in a UserControl and allow me to add a variable number of buttons to each toolbar group.
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
<Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<User_Controls:ImageButton ButtonText="New 1"/>
<User_Controls:ImageButton ButtonText="New 2"/>
<User_Controls:ImageButton ButtonText="New 3"/>
</StackPanel>
<Label HorizontalAlignment="Center" Content="Group 1"/>
</StackPanel>
</Border>
<Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<User_Controls:ImageButton ButtonText="New 4"/>
</StackPanel>
<Label HorizontalAlignment="Center" Content="Group 2"/>
</StackPanel>
</Border>
</StackPanel>
One way to accomplish this is with a custom styled ItemsControl.
You can then reuse it and just bind it to different data.
Please forgive me, this is hand-typed...
In your resources...
<Style x:Key="ToolbarGroupItemsControlStyle" TargetType="ItemsControl">
...
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Grid>
... XAML to form your group with a binding to the
... group name
<ItemsPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="ToolbarGroupItemTemplate">
<Grid>
... XAML and binding for each toolbar group item ...
</Grid>
</DataTemplate>
In your XAML...
<ItemsControl
Style="{DynamicResource ToolbarGroupItemsControlStyle}"
ItemsSource="{Binding ToolbarGroupItems}"
ItemTemplate="{DynamicResource ToolbarGroupItemTemplate"/>
If your resources above are at the application level, then you can place the ItemsControl above on any Window/UserControl you want.
Your ItemsSource will need to be a collection of a custom type you create that has bindings for the button text, etc.
I hope this is helpful.

Layout navigation window

I would like to build a WPF window application using the following layout structure. Consider title and button on left hand frame/window like "Master Pages" in ASP.Net. On the right hand frame it should be a WPF navigation window.
When I include Navigation Window as an UI element at the last stack panel, it throws me and error. How should I design the entire layout according to the image screenshot below? Thanks
<Window x:Class="MainWindow"
xmlns:local="clr-namespace:ClientSocket"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title=" Desktop" Height="841" Width="1271" WindowStartupLocation="CenterScreen" WindowState="Maximized">
<DockPanel>
<StackPanel DockPanel.Dock ="Top" Orientation="Horizontal" Background="Red">
<TextBlock Background="red" FontSize ="36" Width="482" >
Main Title
</TextBlock>
</StackPanel>
<StackPanel Background="LightGray" DockPanel.Dock ="Left" Width="145">
<Button Content="Button1" Name="btnAndroid" Width="119" Margin="3" BorderBrush="{StaticResource {x:Static SystemColors.InfoBrushKey}}" />
<Button Content="Button2" Name="btnDownloads" Width="119" Margin="3" BorderBrush="{StaticResource {x:Static SystemColors.InfoBrushKey}}" />
<Button Content="AddNewDownloads" Height="37" Name="Button1" Width="133" />
</StackPanel>
<StackPanel>
<NavigationWindow Height="auto" Width="auto" Name="nwMain" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderBrush="Blue" BorderThickness="1" />
</StackPanel>
</DockPanel>
</Window>
You cannot add a window as the child of anything, there is a nestable navigation control which you can use here instead, it is called Frame.
Layout-wise i would recommend a Grid with two rows, contains another Grid (in Grid.Row="1") with two columns.
DockPanels are sad controls that probably should not be used, unless someone points a gun at you and tells you to.

In WPF 4.0, switching tabs resets usercontrol UI

I have a border that contains a TabControl in a HeaderedContentControl:
<Border Grid.Column="1"
Style="{StaticResource MainBorderStyle}">
<HeaderedContentControl
Content="{Binding Path=Workspaces}"
ContentTemplate="{StaticResource WorkspacesTemplate}"
Header="Decision Workspaces"
Style="{StaticResource MainHCCStyle}"/>
</Border>
The TabControl is defined in a static resource:
<DataTemplate x:Key="ClosableTabItemTemplate">
<DockPanel Width="120" ToolTip="{Binding Path=DisplayName, Mode=OneTime}">
<Button
Command="{Binding Path=CloseCommand}"
Content="X"
Cursor="Hand"
DockPanel.Dock="Right"
Focusable="False"
FontFamily="Courier"
FontSize="9"
FontWeight="Bold"
Margin="0,1,0,0"
Padding="0"
VerticalContentAlignment="Bottom"
Width="16" Height="16"
/>
<ContentPresenter
Content="{Binding Path=DisplayName, Mode=OneTime}"
VerticalAlignment="Center"
/>
</DockPanel>
</DataTemplate>
<!--
This template explains how to render the 'Workspace' content area in the main window.
-->
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource ClosableTabItemTemplate}"
Margin="4"
/>
</DataTemplate>
The Workspaces property which is bound to the HeaderedContentControl's Content property, has a collection of UserControls, which are rendered in the tabs. This all works fine.
The problem is that when i select a row in a grid in one of the UserControls, switch to a different tab, and then return, the selected row is reset. The same happens if a RowDetails is open - when I switch away and back to the tab, it is collapsed.
Any way around this?
Edit: After looking at the proposed solutions for the TabControl behaviour, I'm wandering if I might ditch it altogether. Any ideas for a UI that will allow me to keep several relatively complex UserControls and switch between them, not loosing the visuals in the process?
Thanks!
This is a common problem with the TabControl. Since it only displays the content of the selected tab. If your tab items are not visuals themselves and are presented with a DataTemplate, then the controls will be created and released as you switch tabs.
There are two solutions to this problem here and here, which attempt to retain the visuals for each tab.

How to dynamically add controls to a Silverlight Button?

I'm working on a Silverlight Polling control. My goal is to have a Button that contains other controls, so that when a user clicks on this combination, stuff happens.
Here's the basic XAML:
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource AnswerButton}">
<StackPanel Grid.Row="1" Grid.Column="0" Height="Auto" Width="Auto" Style="{StaticResource StackPnl}">
<TextBox Text="this is a text box" Style="{StaticResource Answer}" />
<ProgressBar Style="{StaticResource PollProgress}" />
</StackPanel>
</Button>
That works fine, but assume I don't have the StackPanel, etc, defined:
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource AnswerButton}">
</Button>
But that I want to add the StackPanel, TextBox, and ProgressBar at runtime.
Looking at just the first hurdle that I've run into, how do I dynamically add the StackPanel to the Button control?
Alternatively, if someone knows of a better way to do this...
var panel = new StackPanel();
Button.Content = panel;

Resources