Bind a CodeBehind instance of StackPanel to XAML - c#

I have an odd scenario.
I need to create a StackPanel in codebehind. I then need to have that stackpanel bound to the UI in xaml.
Normally I would just use a ContentControl for this. But it has focus issues (it cannot blocked from the tab order Focusable="False" has no effect). I also tried a usercontrol, but that had the same issues.
So I need to use some other kind of control. I have decided on a Panel. (StackPanel seems as good as any of the panels.)
However, I can't seem to find a way to bind to my "In Code" stack panel in my Xaml?
Is there a way to do this? (WITHOUT using a contentcontrol or usercontrol)

it cannot blocked from the tab order Focusable="False" has no effect
What about IsTabStop?
Also the most lightweight thing to use is a ContentPresenter which is what i would use.

Tested this in KAXAML, and the focus doesn't go to any of the items defined in the ContentPresenter or ContentControl when TAB is pressed.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBox>aaaaa</TextBox>
<TextBox>bbbbb</TextBox>
<ContentControl Focusable="False">
<ContentControl.ContentTemplate>
<DataTemplate>
<StackPanel Focusable="False" Background="Red" Width="100" Height="50"></StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
<ContentControl Focusable="False">
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBox Focusable="False">hello</TextBox>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
<ContentPresenter Focusable="False">
<ContentPresenter.Content>
<TextBox Focusable="False">hello</TextBox>
</ContentPresenter.Content>
</ContentPresenter>
<TextBox>ccccc</TextBox>
<TextBox>ddddd</TextBox>
</StackPanel>
</Page>

Related

Change the button style in Expander wpf

How can I change the style of this button? I tried to use Style from the internet, but I got an error every time. I attach 2 screenshots, the original one and how it should look.
The original version
As it should be in the end
<Expander Header="1">
<Border Margin="50,0,0,0">
<StackPanel>
<TextBlock Text="6456567"/>
<TextBlock Text="6456567"/>
<Button Content="111"/>
</StackPanel>
</Border>
</Expander>

General window structure template

for my WPF-application I want a specific window structure for all windows in my application:
<DockPanel>
<UCs:Toolbar DockPanel.Dock="Top"/>
<UCs:SearchPanel DockPanel.Dock="Top"/>
<ContentControl DockPanel.Dock="Top"
Content="{Binding}"/>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Content="Status"/>
</StatusBar>
</DockPanel>
Something like this where I insert the specific user controls in the ContentControl via binding. How can I achieve this?
Because I use this right now for every window:
Window 1:
<DockPanel>
<UCs:Toolbar DockPanel.Dock="Top"/>
<UCs:SearchPanel DockPanel.Dock="Top"/>
<DataGrid .../>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Content="Status"/>
</StatusBar>
</DockPanel>
Window 2:
<DockPanel>
<UCs:Toolbar DockPanel.Dock="Top"/>
<UCs:SearchPanel DockPanel.Dock="Top"/>
<Grid.../>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Content="Status"/>
</StatusBar>
</DockPanel>
If I want to change the order of the toolbar and SearchPanel I have to modify all my windows. I hope there is a way to handle this better...
Thank you in advance
From easy to difficult but elegant:
1-Create a ContentControl that has all the repeated stuff and can host the content which is different in each window. Then in each window, first put your contentcontrol, then your information as its content
2-Create a ControlTemplate for Window and apply it to your windows.

WPF Expander overlay used in ItemsControl

I've been searching for some time but all solution I find only tackle parts of my issue.
I'd like to have an ItemsControl with each item containing an Expander. On expanding, the Expander's content should be shown as an overlay overlapping the other items in the ItemsControl and not moving them down.
The following XAML-Code does exactly as supposed to with one big issue: The Expander's content does not overlap the other items but is hidden behind them. I suppose this is due to the ZIndex as the following items in the ItemsControl are added after the Expander's content.
I managed to set one single Expander's ZIndex to 99 using style triggers but this seems to be a too complicated and error-prone solution. Any thoughts?
<Window x:Class="WpfTest.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">
<Window.Resources>
<x:Array x:Key="items"
Type="sys:String"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String>One</sys:String>
<sys:String>Two</sys:String>
<sys:String>Three</sys:String>
<sys:String>Four</sys:String>
</x:Array>
<DataTemplate x:Key="template">
<Grid Background="Red" Margin="0,0,0,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding}" />
<Canvas Height="25" Grid.Row="1">
<Expander ExpandDirection="Down" Header="Header" Grid.Row="1">
<Expander.Content>
<TextBlock Height="80" Text="Content" Background="Yellow" />
</Expander.Content>
</Expander>
</Canvas>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<ScrollViewer>
<ItemsControl ItemsSource="{StaticResource items}"
ItemTemplate="{StaticResource template}"
HorizontalContentAlignment="Stretch">
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
It's going to be tricky to achieve this in the way you are attempting it. The problem is the nested structure -- since each Canvas is nested inside a Grid, you won't be able to control its z-index relative to other Canvas element. To illustrate this, here is a schematic of the visual tree created by your current markup:
<StackPanel> <!-- items panel -->
<ContentPresenter> <!-- item wrapper -->
<Grid>
<Canvas>
</Canvas>
</Grid>
</ContentPresenter>
<ContentPresenter> <!-- item wrapper -->
<Grid>
<Canvas>
</Canvas>
</Grid>
</ContentPresenter>
</StackPanel>
With reference to the above, your goal will be to have the Canvas elements appear in front of the siblings of its parent ContentPresenter. This is impossible in this hierarchy, because ZIndex only applies relative to siblings of the same parent element. Now, there might be ways you could massage the above into a flat structure so that you could then apply ZIndex your expanded content as needed.
However, I think an easier and more natural approach would be to use Popup elements for the expanded content. A Popup is a framework primitive that is located outside of the visual tree, and will always sit on top of your other content. You can use a ToggleButton or something similar to create the "expand" effect. For example:
<StackPanel Grid.Row="1">
<ToggleButton x:Name="PopupToggle" Content="Expand" />
<Popup IsOpen="{Binding IsChecked,ElementName=PopupToggle}">
<TextBlock Height="80" Text="Content" Background="Yellow" />
</Popup>
</StackPanel>

Changing content according to selected option in WPF

I'm interested in creating an app that displays some buttons and changes a viewport according to the selected button. The viewport in my app is a ContentControl and I thought of changing its content whenever a button is clicked. However, I believe there's a better approach, by perhaps injecting the ViewModels of each of the Views I want to present to the ContentControl and styling them using DataTemplates (Since I want to avoid having a grid with many controls and just setting their Visibility property whenever I want to show a particular view). Which of the approaches seems better to you? Do you have a different approach for this?
The view should be something similar to this:
Thanks!
Usually have a ViewModel behind the window which contains:
ObservableCollection<IViewModel> AvailableViewModels
IViewModel SelectedViewModel
ICommand SetCurrentViewModelCommand
I display the AvailableViewModels using an ItemsControl, which has its ItemTemplate set to a Button. The Button.Command is bound to the SetCurrentViewModelCommand, and it passes the current data item from the AvailableViewModels collection in through the CommandParameter
To display the content area, I use a ContentControl with ContentControl.Content bound to SelectedViewModel, and DataTemplates get used to tell WPF how to render each ViewModel.
The end result is my XAML looks something like this:
<Window.Resources>
<DataTemplate DataType="{x:Type local:ViewModelA}">
<local:ViewA />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelB}">
<local:ViewB />
</DataTemplate>
</Window.Resources>
<DockPanel>
<Border DockPanel.Dock="Left" BorderBrush="Black" BorderThickness="0,0,1,0">
<ItemsControl ItemsSource="{Binding AvailableViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.SetCurrentViewModelCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
CommandParameter="{Binding }"
Margin="2,5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<ContentControl Content="{Binding SelectedViewModel}" />
</DockPanel>
You can view an example of the full code used for such a setup on my blog

ContentPresenter in UserControl

I'm new to WPF and I'm trying to create an UserControl which will have some nested content.
<my:InformationBox Header="General Information" Width="280">
<StackPanel>
<Label>Label1</Label>
<Label>Label2</Label>
</StackPanel>
</my:InformationBox>
As you can see I want to put a StackPanel into it. As I read some articles I am supposed to add ContentPresenter to my UserControl, so I did, but I cannot find what should be binded to it's Content property.
Here is my UserControl code
<UserControl x:Class="ITMAN.InformationBox"
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="200" d:DesignWidth="280" Name="infoBox" Loaded="infoBox_Loaded">
<StackPanel Width="{Binding ElementName=infoBox, Path=Width}" HorizontalAlignment="Stretch">
<Label Content="{Binding ElementName=infoBox, Path=Header}" />
<Border BorderThickness="0,1,0,0" Padding="10 5" Margin="5 0 5 10" BorderBrush="#B4CEDE">
<StackPanel>
<ContentPresenter Content="{Binding Content}" />
<Label Content="End" />
</StackPanel>
</Border>
</StackPanel>
</UserControl>
I've tried many combinations from various articles, but I cannot find any working example of what I want to achieve.
Similiar question was asked earlier by another user, but given there answers didn't help me: Does anyone have a simple example of a UserControl with a single ContentPresenter?
ContentPresenter is kind of a magic control. If you don't supply anything to it, it will automatically set the Content, ContentTemplate and ContentTemplateSelector property with a TemplateBinding to the TemplatedParent. Which means, you don't need to supply anything to it, just
<ContentPresenter/>
in your UserControl, and it should automatically use the corresponding properties found in your UserControl.
Also remember that a binding like {Binding Content} always referes to your DataContext, which i guess is not what you wanted.
I solved this problem by applaying custom style to GroupBox. I've created Syle in ResourceDictionary, which looks as follows
<Style x:Key="InformationBoxStyle" TargetType="GroupBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupBox">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label>
<ContentPresenter Margin="4" ContentSource="Header"
RecognizesAccessKey="True" />
</Label>
<Border Grid.Row="1" BorderThickness="0,1,0,0" Padding="10 5"
Margin="5 0 5 10" BorderBrush="#B4CEDE">
<StackPanel>
<ContentPresenter />
</StackPanel>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And applied this style to GroupBox
<GroupBox Header="General Information" Width="280" Style="{StaticResource InformationBoxStyle}">
<StackPanel>
<Label>Label1</Label>
<Label>Label2</Label>
</StackPanel>
</GroupBox>
This code works as expected
You may also refer to this great article, which shows different options to achieve it:
http://www.codeproject.com/Articles/82464/How-to-Embed-Arbitrary-Content-in-a-WPF-Control
It also describes why ContentPresenter doesn't work in my code.
You need to create a dependency property on your UserControl code behind such as InnerContent.
public object InnerContent
{
get { return GetValue(InnerContentProperty); }
set { SetValue(InnerContentProperty, value); }
}
public static readonly DependencyProperty InnerContentProperty =
DependencyProperty.Register("InnerContent", typeof(object), typeof(ConfirmationControl), new PropertyMetadata(null));
Then you need to bind to that InnerContent on the XAML side of that UserControl.
<ContentControl Content="{Binding InnerContent, ElementName=userControl}" />
Then when you use it instead of placing content in the UserControl directly and overwriting the existing content just add it to the InnerContent portion.
<UserControls:InformationBox>
<UserControls:InformationBox.InnerContent>
<TextBlock Text="I'm in the InnerContent" />
</UserControls:InformationBox.InnerContent>
</UserControls:InformationBox>
Otherwise using a Template or Style is just as good but if you're wanting to package up a UserControl for use without forcing anyone to also reference a style or template this is probably one of your better options.

Categories

Resources