I'm trying to create a control that uses a RevealBorderBrush as its border brush in XAML. I want to use the correct TargetTheme value for the brush, so I'm trying to bind to my application's current ActualTheme value. I'm using a templated control to do this. My C# code behind file is just the empty constructor that inherits from Control and sets the default style key. The following is my Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Plank">
<Style TargetType="local:PlankPL" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:PlankPL">
<Border
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}">
<Border.BorderBrush>
<RevealBorderBrush TargetTheme="{Binding Source=local:App, Path=ActualTheme}"/>
</Border.BorderBrush>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I'm pretty sure the binding statement is incorrect, but I'm not sure how to write it.
I haven't tested this but it should work. Name your control then use the below code, replace ControlTemplateName with what you used.
You can’t bind background data in ResourceDictionary, it doesn’t work.
It is recommended to write a UserControl and bind the RevealBorderBrush property of Border like following.
MyUserControl1.xaml:
<UserControl..>
<StackPanel>
<Border BorderThickness="3">
<Border.BorderBrush>
<RevealBorderBrush TargetTheme="{x:Bind theme1}"/>
</Border.BorderBrush>
</Border>
<TextBox Text = "text demo text "/>
</StackPanel>
</UserControl>
MyUserControl1.xaml.cs:
public sealed partial class MyUserControl1 : UserControl
{
private ApplicationTheme theme1;
public MyUserControl1()
{
this.InitializeComponent();
theme1 = Application.Current.RequestedTheme;
}
}
Related
So I have a ResourceDictionary to define my custom Window style. What I am struggling to do is to access controls from XAML file.
The ResourceDictionary 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="MyCustomWindowStyle" TargetType="{x:Type Window}">
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="30"/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid>
<!-- the root window -->
<Border BorderThickness="0.3" BorderBrush="{DynamicResource GeneralDarkBlue}">
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
</Border>
<DockPanel Height="30" Background="{TemplateBinding Background}" VerticalAlignment="Top" LastChildFill="False">
<Viewbox x:Name="HamburgerMenu" DockPanel.Dock="Left" WindowChrome.IsHitTestVisibleInChrome="True">
<Viewbox.InputBindings>
<MouseBinding MouseAction="LeftClick" Command="{Binding SettingsClick}"/>
</Viewbox.InputBindings>
<Border Width="47" Height="32" Background="Transparent">
<Canvas>
<Path x:Name="TopbarIconHamburgerMenu" Margin="14,10" Data="M12.5,19h19.2v1H12.5V19z M12.5,13.7h19.2v1H12.5V13.7z M12.5,8.5h19.2v1H12.5V8.5z" Stretch="UniformToFill" Fill="#FFFFFF"/>
</Canvas>
</Border>
</Viewbox>
// the rest of viewboxes for minimize, maximize controls...
</DockPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And let's say I want to access the HamburgerMenu, so I do something like this
public partial class MyCustomWindowStyle : ResourceDictionary
{
public MyCustomWindowStyle()
{
InitializeComponent();
}
public void DoSomething()
{
var window = (Style)Application.Current.Resources["MyCustomWindowStyle"];
var hm = (Viewbox)window.Resources.FindName("HamburgerMenu");
}
}
and this returns null in the hm!
Any idea how to do this?
First of all, Style.Resource is a ResourceDictionary, and there are two important things to notice in the ResourceDictionary.FindName method documentation:
Summary section saying:
Not supported by this Dictionary implementation.
and Return Value section saying:
Always returns null.
Second of all, even if you tried to retrieve the ViewBox by key, it would have to be defined as a resource:
<Style x:Key="MyCustomWindowStyle" TargetType="{x:Type Window}">
<Style.Resources>
<ViewBox x:Key="HamburgerMenu" />
</Style.Resources>
</Style>
And it is not. It is a part of ControlTemplate's visual tree.
Third of all, ControlTemplate does not contain actual elements, but rather a recipe for creating them. So there's no actual ViewBox living inside the ControlTemplate to retrieve. Notice that ControlTemplate.FindName takes an additional parameter specifying an element for which the template was realized.
However, ControlTemplate does have a LoadContent method, which basically loads the visual tree defined by that template, and I think you could use it, and then invoke FindName on the root element. To simplify retrieval of the ControlTemplate let's first make it a resource:
<Style x:Key="MyCustomWindowStyle" TargetType="{x:Type Window}">
<Style.Resources>
<ControlTemplate x:Key="Template" TargetType="{x:Type Window}">
<Grid>
(...)
<ViewBox x:Key="HamburgerMenu" />
(...)
</Grid>
</ControlTemplate>
</Style.Resources>
<Setter Property="Template" Value="{StaticResource Template}" />
</Style>
Then this should do the trick for you:
var window = (Style)Application.Current.Resources["MyCustomWindowStyle"];
var template = (ControlTemplate)window.Resources["Template"];
var root = (FrameworkElement)template.LoadContent();
var hm = (ViewBox)root.FindName("HamburgerMenu");
Update
If your goal is to get hold of the ViewBox in an existing window with that template applied, first you need to know how to get hold of that particular window. It could be the Application.Current.MainWindow, otherwise you're highly likely to find it in the Application.Current.Windows collection. You could also implement the singleton pattern for that window, or use other methods like exposing a static property with reference to that window somewhere in your application, or using third-party tools, such as Service Locator in Prism.
Once you have the window in your hand, you only need to use the previously mentioned ControlTemplate.FindName method:
var window = (...);
var hm = (ViewBox)window.Template.FindName(name: "HamburgerMenu", templatedParent: window);
Note that accessing the resource dictionary in which the template was defined is not necessary.
As for why your attempts with previous solution failed - that's because ControlTemplate.LoadContent method yields freshly created element each time it is invoked, and modifying it does not reflect on elements previously created by that template.
I have a ContentControl is defined in XAML like this:
<ContentControl Width="100"
Height="100"
Canvas.Top="100"
Canvas.Left="100"
Template="{StaticResource DesignerItemTemplate}">
<Ellipse IsHitTestVisible="False" Fill="Blue"/>
</ContentControl>
And I want to create another one by code but I don't know how to set the Template property. Anyone can help me, please?
Write the Template in some ressources (App, Window, Grid, whatever, ...)
<Window>
<Window.Resources>
<ControlTemplate x:Key="DesignerItemTemplate" TargetType="{x:Type ContentControl}">
<Border BorderBrush="Red" BorderThickness="1">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Window.Resources>
</Window>
In code behind, find the resource and assign the Template :
public MainWindow()
{
InitializeComponent();
contentControl1.Template = Resources["DesignerItemTemplate"] as ControlTemplate;
}
Regards
Try using
Test.Template=Application.Current.FindResource("DesignerItemTemplate")
I am modifying the Header of a TabItem to conditionally display an Image, which led me to this MSDN article: HeaderedContentControl.Header Property. I attempted the code and substituted in my conditional image, which does what I expect.
However, the image in that example shows the TabItems with a different style than what I got when I ran my example. Where can I get the style for the slanted TabItems in the MSDN example?
Did you also apply the style for the HeaderedContentControl from the example?
<Style TargetType="HeaderedContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedContentControl}">
<StackPanel>
<Grid>
<Rectangle Stroke="{TemplateBinding Background}"/>
<ContentPresenter ContentSource="Header"/>
</Grid>
<Grid>
<Rectangle Fill="{TemplateBinding Background}"/>
<ContentPresenter ContentSource="Content"/>
</Grid>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This overrides the default ControlTemplate of the control. Also, if you use TabControl instead of HeaderedContentControl, it is possible that the results vary.
I trying to create a custom textbox control in windows 8 XAML.
I've right clicked on my project -> Add -> New Item
I've then selected Templated Control and entered the name MyTextBox
I have then made this class derive from TextBox and added a test Method called Hello. So it now looks like this:
public sealed class MyTextBox : TextBox
{
public MyTextBox()
{
this.DefaultStyleKey = typeof(MyTextBox);
}
public void Hello()
{
//Do something here!
}
}
Within my project a file has also been added called Generic.xaml with the following style:
<Style TargetType="local:MyTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyTextBox">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So within here I tried adding BasedOn="TextBox" with the Style tag:
<Style TargetType="local:WatermarkTextBox" BasedOn="TextBox">
This doesn't work.
What do I need to do to create this custom TextBox and then how do I use it within my XAML
This is for a Windows RT so the XAML maybe different from WPF.
One of best article and my favorite : Building a deployable custom control for XAML Metro style apps
Here is MSDN sample app : XAML user and custom controls sample
UPDATE 1 :
<Style TargetType="local:WatermarkTextBox" BasedOn="TextBox">
You don't have to specify BasedOn attribute. If you are developing watermark textbox then I would recommend you to check Callisto's watermark textbox code.
Generic.xaml
WatermarkTextBox.cs
BasedOn values can be pointed through StaticResources like BasedOn={StaticResource DefaultTextBoxStyle}
I have a NumericOnlyTextBox implementation. Instead of making it BasedOn textbox I've added a textbox and all its dependencies.
In example:
<Style TargetType="local:NumericOnlyTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:NumericOnlyTextBox">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel>
<TextBox x:Name="TextBoxPart"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EnteredText, Mode=TwoWay}"
MaxLength="{TemplateBinding MaxLength}">
</TextBox>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsTabStop" Value="False"></Setter>
</Style>
I have a user-control and I want to use it in some other project. There is no problem when I set some value to its properties directly:
<local:MyUserControl prop1="val1" prop2="val2">
...
</local:MyUserControl>
But I can't apply a style to it. I tried:
<Window ...>
<Window.Resources>
<Style x:Key="MyUserControlStyle" TargetType="{x:Type local:MyUserControl}">
<Setter Property="prop1" Value="val1"/>
<Setter Property="prop2" Value="val2"/>
</Style>
</Window.Resources>
<Grid>
<local:MyUserControl Style="{StaticResource ResourceKey=MyUserControlStyle}">
...
</local:MyUserControl>
</Grid>
</Window>
Where did I wrong? -Thanks
Using dear #Mario Vernari's instructions, I found it out that the problem was due to a bad strategy which I'd used to create my UserControl. I wanted to create a UserControl that be able to hold some other ones. So I had tried this:
<UserControl x:Class="MyNamespace.MyUserControl"
...
Style="{DynamicResource ResourceKey=MyUserControlStyle}">
<UserControl.Resources>
...
<Style x:Key="MyUserControlStyle" TargetType="{x:Type UserControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type UserControl}">
<Border BorderBrush="{Binding Path=DP1}">
...
<ContentPresenter ... Content="{TemplateBinding Content}"/>
...
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
</UserControl>
Where DP1 is a dependency property of type Brush. The UserControl which has been created through this way works if you set its properties (like DP1) directly. Absolutely this is not the true way as #Mario told me:
...When you use an UserControl, it means that you already know its layout, and there is no need to style the control further. You are defining its style twice at the same time thus results a collision...
And he added:
Instead, you should use a CustomControl; Define the default style in the Themes folder (if you own regular Visual Studio, it makes automatically). Afterward, you may override the default style in your own app. In the same way you would do for a normal base class and its derived.
Follow this:
http://www.codeproject.com/KB/WPF/WPFCustomControl.aspx ...
Obviously, in this case we need to derive our lookless control from ContentControl class (instead of Control class). You may take a look at this & this to master the details.
Here, I give thanks to #Mario again. ;)
You are giving Style="{StaticResource ResourceKey=MyUserControlStyle}".
It's just - Style="{StaticResource MyUserControlStyle}".