HeaderedContentControl header template not being used - c#

I'm fairly new to WPF and am working with some legacy code, not sure how to use the HeaderedContentControl Header. I'd like to put in a StackPanel and customize the look of a header, just not sure how to do that.
Could someone give me some guidance on what to do next?
I have this xaml and the HeaderTemplate is never used.
<UserControl x:Class="PEC.Admin.WindowsControls.Program.Views.ProgramProductEnrichmentColorsView"
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"
xmlns:commonControls="clr-namespace:ManagerConsole.Common.Controls;assembly=ManagerConsole.Common.Controls"
xmlns:program="clr-namespace:PEC.Admin.ViewModel.Program;assembly=PEC.Admin.ViewModel.Program"
mc:Ignorable="d"
d:DesignWidth="300"
d:DataContext="{d:DesignInstance program:ProgramProductEnrichmentColorsViewModel}">
<commonControls:ExpanderPanel IsExpanded="{Binding Path=IsExpanded,Mode=TwoWay}">
<HeaderedContentControl.HeaderTemplate> <!-- this never gets used... -->
<DataTemplate>
<StackPanel>
<Label Content="{Binding Path=Header}"></Label>
</StackPanel>
</DataTemplate>
</HeaderedContentControl.HeaderTemplate>
<StackPanel HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Width="Auto"
Margin="3"
Background="White">
<TextBlock Text="Source Type:"
Margin="0,5,0,0" />
<TextBox IsReadOnly="True"
IsTabStop="False"
Background="LightGray"
BorderThickness="0"
Text="{Binding Path=SourceTypeName, Mode=OneTime}" />
</StackPanel>
</commonControls:ExpanderPanel>
</UserControl>

HeaderTemplate is applied. To verify it - set a background to the Label in HeaderTemplate.
HeaderTemplate doesn't display anything though, because binding is incorrect. Template is applied to the data set in Header property, which currently has null value.
So change code as in the example below (I tried with Expander, hopefully it will work for custom commonControls:ExpanderPanel):
<Expander IsExpanded="{Binding Path=IsExpanded, Mode=TwoWay}"
Header="{Binding ComplexObject}">
<HeaderedContentControl.HeaderTemplate>
<DataTemplate>
<StackPanel>
<Label Background="Green" Content="{Binding PropertyOfTheObject}"/>
</StackPanel>
</DataTemplate>
</HeaderedContentControl.HeaderTemplate>
</Expander>
Header is a dependency property and can be set via Binding. Header becomes a source for bindings in a HeaderTemplate. Or it can be some constant (Header="Click to expand"), resource (Header="{StaticResource ExpandTitle}") or complex content, e.g.:
<Expander.Header>
<TextBlock Text="Click to expand"/>
</Expander.Header>

Related

Element inside Flyout in XAML isn't accessible from Code Behind

I'm working on a UWP application and need some help with Flyout. I have a Flyout in my XAML with a few TextBlock elements but don't seem to be able to call those elements in the Code Behind. Everytime I try that, I get an Exception "The name TB does not exist in the current context."
I already searched for possible solutions and tried the following things: Made a clean build, Restarted VS 2017, Cleared the bin folder manually and then tried to rebuild
But nothing seems to work and I'm on a point where I don't know what to do.
<Page
x:Class="FuhrparkUWP.Pages.Parkhaeuser"
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:converter="using:FuhrparkUWP.Converter"
xmlns:data="using:FuhrparkStructureUWP.Model"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<converter:PassendFuerToStringConverter x:Key="PassendFuerToStringConverterKey"></converter:PassendFuerToStringConverter>
<converter:BelegtStatusToImageConverter x:Key="BelegtStatusToImageConverterKey"></converter:BelegtStatusToImageConverter>
</Page.Resources>
<Grid>
<ComboBox Name="CmbSelectParkhaus" Header="Parkhaus" HorizontalAlignment="Center" VerticalAlignment="Top" Width="200" SelectionChanged="CmbSelectParkhaus_SelectionChanged"/>
<GridView ItemsSource="{x:Bind Parkplaetze}" Name="ContentGrid" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0, 100, 0, 0">
<GridView.ItemTemplate>
<DataTemplate x:Name="ImageTextDataTemplate" x:DataType="data:Parkplatz">
<StackPanel Height="280" Width="180" Margin="12" Tapped="Content_Tapped">
<Image Source="{Binding Path=IstBelegt, Converter={StaticResource BelegtStatusToImageConverterKey}}" Height="180" Width="180" Stretch="UniformToFill"/>
<StackPanel Margin="0,12">
<TextBlock Text="{x:Bind FahrzeugKennzeichen}"/>
<TextBlock Text="{Binding Path=PassendFuer, Converter={StaticResource PassendFuerToStringConverterKey}}" Style="{ThemeResource CaptionTextBlockStyle}" Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"/>
</StackPanel>
<FlyoutBase.AttachedFlyout>
<Flyout>
<StackPanel>
<Image Source="/Assets/Images/ParkplatzFrei.png" Width="180" Height="180"></Image>
<TextBlock Name="TB"></TextBlock>
<TextBlock Text="Passend für: LKW, PKW, Motorrad"></TextBlock>
<TextBlock Text="Belegt durch: FREI"></TextBlock>
</StackPanel>
</Flyout>
</FlyoutBase.AttachedFlyout>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
</Page>
I expect to call TB.Text = "xyz" for example from the Code Behind page, but at the moment I'm not able to call it.
I'm still able to call the other elements outside from the Flyout like "CmbSelectParkhaus" though.
You cannot handle things inside a DataTamplate, datamplates are not actual ui entities, they are Templates.
Assuming you want to achieve the same kind of access across all of your GridView items, you have to attach dependency properties, and either create programmatic binds on the PrepareContainerForItemOverride or the appropriate xaml "{Binding}" expressions.
This just opens whole new rabbit hole, especially if you are unaware of at least a single thing i mentioned so far, but you can just look up the bolded words one by one.

WPF: How to access element in ResourceDictionary code behind

In my application I have a control which renders a number of blocks on a timeline view (like a calendar). One can provide a template for the blocks by giving the timeline an appropriate DataTemplate.
I would like to separate the block DataTemplate from the main timeline view, putting the block into its own XAML. As such, I've created a XAML for the Block (called Block.xaml) and wrapped the DataTemplate inside a ResourceDictionary, inside this XAML.
I've added a code behind to the XAML (called Block.xaml.cs) in which I need to access some of the elements in the block. The issue is that ResourceDictionaries seem to hide the elements from the codebehind such that I can't access them. I can't use a UserControl instead - this seems to not work.
How can I access the elements of the Block DataTemplate from the code behind?
Many thanks in advance for your help.
Block.xaml:
<ResourceDictionary x:Class="Project.Windows.MainInterface.TimelinePanel.Block" 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:local="clr-namespace:Project.Windows.MainInterface.TimelinePanel" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:converters="clr-namespace:Project.Converters" >
<DataTemplate x:Key="ItemBlockTemplate">
<Grid Name="BlockParent" Width="Auto" Height="Auto" MinHeight="50" ClipToBounds="True" SizeChanged="BlockParent_OnSizeChanged">
<Border Panel.ZIndex="3" BorderBrush="{DynamicResource BackgroundGreyLight}" BorderThickness="1" CornerRadius="1" />
<Grid Margin="1" Background="{DynamicResource BlockBackgroundGradient}" d:LayoutOverrides="Width">
<TextBlock x:Name="blockName" Height="20" Margin="4,0,4,0" Padding="3" VerticalAlignment="Top" Panel.ZIndex="3" FontSize="10" Foreground="{DynamicResource TextLight}" Text="{Binding blockName}" TextTrimming="CharacterEllipsis" Visibility="Visible" />
<TextBlock x:Name="Duration" Margin="0,2,4,2" Padding="0,0,3,0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Panel.ZIndex="5" FontSize="10" Foreground="{DynamicResource TextLight}" Text="{Binding FormattedDuration}" ToolTip="{Binding Duration}" />
<Grid Background="#FF0FA8FF" Opacity="0.7" />
</Grid>
</Grid>
</DataTemplate>
Snippet of the Timeline in the main interface:
...
<timeLineTool:TimeLineControl x:Name="Timeline" Height="50" MinWidth="50" Margin="0,0,12,0" HorizontalAlignment="Left" VerticalAlignment="Top" Items="{Binding Timeline}" SnapsToDevicePixels="True" UnitSize="{Binding UnitSize}" UseLayoutRounding="True">
<timeLineTool:TimeLineControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:BlockItemViewModel}">
<ContentControl>
<ContentPresenter Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="{Binding}" ContentTemplate="{StaticResource ItemBlockTemplate}" />
</ContentControl>
</DataTemplate>
</timeLineTool:TimeLineControl.ItemTemplate>
</timeLineTool:TimeLineControl>
...
...If I could use a UserControl instead of a ResourceDictionary for my Block, this would solve the problem, as all elements are automatically publicly available in the code behind for usercontrols.
Sample XAML:
<Window.Resources>
<ControlTemplate x:Key="ResourceName" TargetType="{x:Type Label}">
<Label Foreground="White" Content="{iconPacks:PackIconFontAwesome plug,Height=40,Width=40}"/>
</ControlTemplate>
</Window.Resources>
Code behind
ControlTemplate Dictionary:
private Dictionary<string, ControlTemplate> collection
{
get
{
Dictionary<string, ControlTemplate> controlTemplates = new Dictionary<string, ControlTemplate>();
controlTemplates.Add("ResourceName", FindResource("ResourceName") as ControlTemplate);
return controlTemplates;
}
}
Use ControlTemplate:
Label LBDisConnect = new Label();
LBDisConnect.Template = collection["ResourceName"];
LoginInfo.Children.Add(LBDisConnect);

Responsive Windows App Element

Is there any XAML element that will automatically wrap to a new line for sub elements that don't have enough room on a line?
What I mean is that on a wide screen I'll get:
Box1 Box2 Box3
And on a narrow one:
Box1 Box2
Box3
Without having to listen to events and fix it by code.
The comments mention VariableSizedWrapGrid as a solution. But I can't figure out how to make it wrap.
You can use a simple GridView to do it. If you don't set a Height, it should work like a charm.
<GridView Name="xConcerts" ItemsSource="{x:Bind Artist.UpcomingEvents, Mode=OneWay}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="songkick:EventExt">
<Border CornerRadius="8" Background="{ThemeResource ThemeGrayHighColorBrush}" Opacity="0.8">
<StackPanel Margin="18,2">
<TextBlock Text="{x:Bind FullDisplayDate, Converter={StaticResource FormatStringToDateDayConverter}}" Style="{ThemeResource ThemeDateBoldStyle}"/>
<TextBlock Text="{x:Bind FullDisplayDate, Converter={StaticResource FormatStringToDateMonthConverter}}" Style="{ThemeResource ThemeDateBoldStyle}" Margin="0,-4,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemContainerTransitions>
<TransitionCollection>
<RepositionThemeTransition/>
</TransitionCollection>
</GridView.ItemContainerTransitions>
</GridView>
According to your requirement, using the WrapPanel control in WinRTXamlToolkit will meet your needs.
Sample code here:
<Page x:Class="TestDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Tool="using:WinRTXamlToolkit.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TestDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Tool:WrapPanel>
<Button Width="200" Margin="10">1</Button>
<Button Width="200" Margin="10">2</Button>
<Button Width="200" Margin="10">3</Button>
</Tool:WrapPanel>
</Page>
And the output here:

Make WPF App Accessible to screen reader

I have a WPF application and part of the requirements are that it is accessible, including keyboard navigation and screen readers.
I have had some success with a a Treeview in the application by setting the AutomationProperties.Name in the ItemContainerStyle of the Treeview, but I am having problems with a Window that contains a text area and some buttons.
ZoomText will correctly read out the Title of the Window, but do so twice, as well as the text in the buttons, but I cannot get it to read the contents of the TextBlock.
The Text block is defined in a window as below. There are no binding errors showing up in the Visual Studio output while debugging, and the NVDA screen reader can read the content correctly, although this is not good enough for me as the customer uses ZoomText.
<Window x:Class="UserControls.ModalDialog"
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="160" d:DesignWidth="400" MinHeight="85" MinWidth="400" MaxWidth="400" SizeToContent="Height" Height="Auto"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize" Title="{Binding TitleText }">
<DockPanel Width="Auto" Margin="20,20,0,10">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=DialogText, Mode=TwoWay}" Cursor="Arrow" Focusable="True" TextWrapping="WrapWithOverflow"
Height="Auto" Width="325" TextOptions.TextFormattingMode="Display"
ToolTip="{Binding Path=Text, RelativeSource={RelativeSource Self}}"
AutomationProperties.Name="{Binding Path=Text, RelativeSource={RelativeSource Self}}"
AutomationProperties.AutomationId="{Binding Path=Text, RelativeSource={RelativeSource Self}}">
</TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,5,0">
<Button Content="{Binding Path=Option1ButtonText, Mode=TwoWay}" Padding="5,0,5,0" Margin="0,20,5,0" MinWidth="100" IsDefault="True" Command="{Binding Path=Option1ButtonCommand, Mode=TwoWay}" />
<Button Content="{Binding Path=Option2ButtonText, Mode=TwoWay}" Padding="5,0,5,0" Margin="2,20,10,0" MinWidth="75" Command="{Binding Path=Option2ButtonCommand, Mode=TwoWay}" Visibility="{Binding Option2ButtonVisibility, Mode=TwoWay}"/>
<Button Content="{Binding Path=CancelButtonText, Mode=TwoWay}" Padding="5,0,5,0" Margin="2,20,10,0" MinWidth="75" IsCancel="True" Visibility="{Binding CancelButtonVisibility, Mode=TwoWay}"/>
</StackPanel>
</StackPanel>
</DockPanel>
If anyone has had any success with WPF and Screen readers and has any insight, or can point me in the right direction it would be great.
Update:
It seems the problem is because the TextBlock is within another element. If the window has the TextBlock as it's only element the screen reader reads the text correctly. However I need the Dock and Stack Panels for layout, so I need to find a way to get the Screen reader to work when the TextBlock is not the only content in the window.
You can do pretty much everything you need using the Automation Properties
For example;
Name
HelpText
Labels / LabeledBy
See documentation for more details on usage. Kind of surprised this wasn't answered by now considering the amount of upvotes. Either way, hope this helps. Cheers!

Adding custom class with XAML in ListBox C# WPF

I have a class PC that contains Image, Label (with XAML design) and I want to get a list of PCs in ListBox in other class.
I tried this, but I get error System.Windows.Markup.XamlParseException:
pc p = new pc();
list_pc.Items.Add(p);
(where list_pc is a ListBox)
This is the XAML for a single PC:
<Window
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" mc:Ignorable="d"
x:Class="TnCyberCafe.pc"
Title="pc"
SizeToContent="WidthAndHeight"
ShowInTaskbar="False"
WindowStartupLocation="CenterScreen"
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent" Width="95" Height="104.982">
<Grid HorizontalAlignment="Left" Margin="0,10,-15,10" Width="110">
<Image x:Name="image" HorizontalAlignment="Left" Height="96" VerticalAlignment="Top" Width="100" Source="Resources/aaa.png" RenderTransformOrigin="0.5,0.26" Margin="0,-16,0,0"/>
<Label Content="Label" HorizontalAlignment="Left" Height="25" Margin="20,70,0,-10" VerticalAlignment="Top" Width="45"/>
</Grid>
</Window>
This is the XAML for my list_pc:
<ListBox x:Name="liste_pc" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
List PCs
</ListBox>
Your first question regarding the System.Windows.Markup.XamlParseException:
As Garry Vass mentioned something went wrong, but does not tell you exactly what happened. If you are developing in Visual Studio, Click on Exceptions under Debug Tab and enable Common Language Runtime Exceptions. This will point you to the Error Code.
For the second question you should have databindings and ListBox Itemtemplate as below
<ListBox x:Name="liste_pc" ItemsSource="{Binding PCList}" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding PCImageSource}" />
<Label Content="{Binding Path=PCName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
where PCList is the observable collection of PC Class object items

Categories

Resources