Create custom Template Control which accepts child content - winrt-xaml

This a pretty basic question that I can't find a simple answer to anywhere online. In a Windows Store xaml/c# app, if I create a New Templated Control named CustomControl1.cs.
Here's the default template as defined in the Generic.xaml file:
<Style TargetType="local:CustomControl1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomControl1">
<Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I should be able to specify where child content lives by setting the Content property on the Border element above in either of the two following ways.
Specify content as Attribute
<Border Child="{TemplateBinding Content}" />
Specify content as Element
<Border>
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}" />
</Border>
But in either event, whenever I use the new control elsewhere, I'm unable to set the content property
Using this:
<local:CustomControl1>
<Button></Button>
</local:CustomControl1>
Gives off the two following errors:
Cannot add content to an object of type "CustomControl1"
The type 'CustomControl1' does not support direct content.

Make sure you derive your class from ContentControl and not just Control. This should resolve this for you. The default "Templated Control" item template is pretty generic to handle any case that folks might want, so if you want something more (in this case a Content control), just change to derive from ContentControl.
Hope this helps!

Related

Custom themed controls declared in base page

I have some Styles-Files.
For example ButtonStyles.xaml looks like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style
x:Key="CustomButtonStyle"
TargetType="Button">
<Setter
Property="Foreground"
Value="White" />
<Setter
Property="Background"
Value="Black" />
<Setter
Property="Height"
Value="32" />
</Style>
<Style
TargetType="Button"
BasedOn="{StaticResource CustomButtonStyle}">
</Style>
</ResourceDictionary>
And I have Pages which extend from my BasePage.
If I want my new Styles to override the controls I have to add this Code in every Page:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Styles/ButtonStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
However if I have this code in my BasePage it won't theme my controls.
Is there a way to import my styles in every Page without copy-pasting this code over and over?
I can't reproduce this issue with using BasePage in my side. It would be better if you can post a sample that can reproduce your issue.
However, to use the custom styles in every page, I recommend merging resource dictionaries into Application.Resources. Application.Resources is the best place to put any app-specific resources that are referenced by multiple pages in your app's navigation structure. If the requested resource is not found in the Page.Resources, the XAML resources system will tries to check the Application.Resources property. So if we merged resource dictionaries into Application.Resources, we can use them in all pages of the app. And if we want to use some different styles in certain pages, we can specify new Style in their Page.Resources. For more information, see Lookup behavior for XAML resource references.
So we can merge resource dictionaries into Application.Resources like following:
(Note that ../Styles/ButtonStyles.xaml can't be used in WinRT XAML, we should use "/" to refer to the package root.)
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/ButtonStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Then in other pages, if we don't specify the Style for Button, it will use the style defined in ButtonStyles.xaml.

How do I cascade Styles in a Universal Windows Platform app?

I am yet again struggling with UWP. It seems that I am unable to cascade Styles within Styles. Is this something else that is not allowed in UWP?
This is what I am trying to do...
<Style x:Key="MainMenuRadioButtonStyle" TargetType="RadioButton">
<Setter Property="Backgroud" Value="Grey"/>
<Style.Resources TargetType="TextBlock">
<Setter Property="Margin" Value="12,0,0,0"/>
</Style.Resources>
</Style>
However, VS2015 complains that the <Style.Resources> is invalid. I do not want to have to individually style the TextBlock within my RadioButton's content.
Cascading within styles not supported in UWP (or XAML in general). What you usually do is split up re-usable styles/properties and reference those.
<Thickness x:Key="MyMargin">"12,0,0,0"</Thickness>
<Style x:Key="MainMenuRadioButtonStyle" TargetType="RadioButton">
<Setter Property="Background" Value="Grey"/>
<Setter Property="Margin" Value="{StaticResource MyMargin}" />
</Style>
What you try to achieve is 'alter' the template of a RadioButton. You can find the full template here: https://msdn.microsoft.com/en-us/library/windows/apps/mt299147.aspx. If you dig into the template, you'll see this piece of code:
<ContentPresenter x:Name="ContentPresenter"
Content="{TemplateBinding Content}"
ContentTransitions="{TemplateBinding ContentTransitions}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Grid.Column="1"
AutomationProperties.AccessibilityView="Raw"
TextWrapping="Wrap" />
This is the part that's showing the actual content of your RadioButton and as you can see it's not a TextBlock, but a ContentPresenter (which will show text as if it was a TextBlock). The good news is that this control has a Margin property, which takes the value of the Padding property from the template. So to achieve what you want, you can simple fill in this property:
<Style x:Key="MainMenuRadioButtonStyle" TargetType="RadioButton">
<Setter Property="Background" Value="Grey"/>
<Setter Property="Padding" Value="{StaticResource MyMargin}" />
</Style>
If you want to change properties that are not available in the default template, then you'll have to create your own template.

How to display all the elements on the same point using ItemsControl wpf

I want to disply all my elipse in the same point using itemControl wpf. by default itemsControl use vertical stackpanel. there's a way to simply remove the StackPanel?
Thanks
Sure, you can give a custom ItemsPanel by either set one in your ItemsControl ControlTemplate, and using the IsItemsHost property to tell which of the panels is the receiver of the items.
<ItemsControl.Template>
<ControlTemplate>
<Canvas IsItemsHost="True"/>
</ControlTemplate>
</ItemsControl.Template>
or by supplying a custom ItemsPanel and telling the position in the template by an ItemsPresenter.
<ItemsControl.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

WPF window template resource

I am trying to define a window template that can be used by windows in other assemblies. I define a window template and store it in resource dictionary in some assembly. After, I use this template in other assembly on window definition in XAML. It looks that the template is accepted and I can see updated window in VS-2010 designer but when I add a new control to this window, the control disappears from window but still exists in XAML code. I also tried to apply the same template explicitly and it works well.
Xaml code of generic.xaml in project that contains template definition, the ThemeInfo attribute is set and BuildAction property for this file is Page.
<ControlTemplate x:Key="{ComponentResourceKey TypeInTargetAssembly= {x:Type local:DialogResources}, ResourceId=DialogTemplate}">
<Border Width="Auto" Height="Auto" Name="windowFrame"
BorderBrush="#395984"
BorderThickness="1"
CornerRadius="0,20,20,20"
Background="AliceBlue">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Margin="1" Padding="5" Text="Template Window" FontWeight="Bold"/>
<Border Background="#B5CBEF" Grid.Row="1" CornerRadius="0,0,20,20" >
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</Border>
</Grid>
</Border>
</ControlTemplate>
DialogRespources - is an empty class that defined in MyProg.Resources assembly.
Now I use this template in other assembly like this:
In this window I add a button but I can't to see it. When I define the TemplateControl explicitly (without using resource) I can see it.
The other problem is that I get a following designer exception when use TargetType="{x:Type Window}" for template in resource: "'Window' ControlTemplate TargetType does not match templated type 'WindowInstance'." I could not find anything regarding this exception in Google.
Please, help me to understand what is wrong in my code?

Silverlight / WPF Custom Control Template Help

I'm hoping to create a control that I call an "AutoCompleteListBox". If you've ever used hotmail to send an e-mail the way the to: address line works is what I wish to create. You have what looks like an input box and as you type you get a dropdown of matching objects. Once you select an object (contact) it is added into the input box as a rectangular object. Multiple objects can be added this way and the input box acts like a wrap panel. You can delete objects by backspacing them or clicking the x button on each.
My approach was to begin by subclassing ItemsControl. I've started to write its control template which is basically a wrap panel that I want to show the bound items + a text box. I don't know how to get both the bound items and the textbox to be in the same wrap panel. Here's what I have:
<Style TargetType="ctrl:AutoCompleteListBox">
<Setter Property="Width" Value="200"/>
<Setter Property="Height" Value="100"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ctrl:AutoCompleteListBox">
<ScrollViewer x:Name="RootScrollViewer" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Padding="0" Background="{TemplateBinding Background}">
<toolkit:WrapPanel IsItemsHost="True">
<!--Items Bound To ItemSource Go Here-->
<TextBox x:Name="txtInput"/>
</toolkit:WrapPanel>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I don't know how to express what I want. I know you can use an "ItemsPresenter" in the control template which does show the bound items but then how can I add my textbox into the same panel as the bound items?
I'd greatly appreciate any help. Is this the right way to even go about it? Thanks very much.
Subclassing the items control is a good start, but I think the controltemplate should be setup a bit different. The Silverlight toolkit contains an excellent autocomplete box that you can use for this exact purpose. Combine this with a separate items control and you should have something that can be styled to look exactly like the live mail "To" field.
<ControlTemplate>
<toolkit:WrapPanel>
<ItemsControl ItemsSource="{TemplateBinding Items}">
<ItemsControl.ItemsPanel>
<StackPanel Orientation="Horizontal"/>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<!-- Add data template for the previously added items here -->
</ItemsControl.ItemTemplate>
</ItemsControl>
<toolkit:AutoCompleteBox ItemsSource="{TemplateBinding AutoCompleteItems}" />
</toolkit:WrapPanel>
</ControlTemplate>

Resources