mysterious runtime error in applying a template to wpf window - c#

i have a hard problem dealing with template. please help me.
App.xaml
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
//Note i didn't set a StartupURI in Application tag please.
<Application.Resources>
<Style TargetType="Window" x:Key="myWindowStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Rectangle Fill="gray" RadiusX="30" RadiusY="30"/>
<ContentPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
App.xaml.cs
using System;
using System.Windows;
namespace WpfApplication1
{
public partial class App : Application
{
CMainWindow winMain;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
winMain = new CMainWindow();
winMain.ShowDialog();
}
}
}
CMainWindow.xaml
<Window x:Class="WpfApplication2.CMainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Style="{StaticResource myWindowStyle}" Background="Red">
</Window>
=====================
question #1
when run this program, ide occure a runtime error : XmlParseException.
so i add a line in app.xaml, it runs properly. that line is : StartupUri="CMainWindow.xaml".
what is this? what relationship between template and startupuri? please tell me about this.
question #2
when i add control to CMainWindow, it didn't apeear even i set a in window's template.
how can i add control properly in this situation?
thanks.

question #1
A WPF application is always centered around a window. You're override of OnStartup is unnecessary. By setting the StartupURI the application will automatically start by displaying the window.
There is no actual relationship between template and startupuri. You just happen to be using App.xaml to store global styles.
question #2
The magic field to add is "TargetType" on the control template. You have to explicitly say its for the window type.
<Application x:Class="SimpleWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="Window" x:Key="myWindowStyle">
<Setter Property="Template">
<Setter.Value>
<!-- Explicitly setting TargetType to Window -->
<ControlTemplate TargetType="Window">
<Grid>
<Rectangle Fill="gray" RadiusX="30" RadiusY="30"/>
<ContentPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>

Related

ContentControl does not show content in ControlTemplate

I need to create a custom control similar to WPF GroupBox. I started from the standard WPF Custom Control Library template in VS 2015 and defined my CustomGroupBox control like this:
public class CustomGroupBox : ContentControl
{
static CustomGroupBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomGroupBox), new FrameworkPropertyMetadata(typeof(CustomGroupBox)));
}
}
Then added the following minimal set of lines to develop my custom GroupBox according to the specification:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomGroupBox">
<Style TargetType="{x:Type local:CustomGroupBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomGroupBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="Gray" BorderThickness="3" CornerRadius="3">
<ContentControl />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
To debug and develop, I created a test form for my custom control:
<Window x:Class="CustomGroupBoxClient.MainWindow"
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:local="clr-namespace:CustomGroupBoxClient"
xmlns:ctrl="clr-namespace:CustomGroupBox;assembly=CustomGroupBox"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ctrl:CustomGroupBox Margin="5">
<StackPanel Orientation="Vertical">
<TextBlock>Text Block #1</TextBlock>
<TextBlock>Text Block #2</TextBlock>
</StackPanel>
</ctrl:CustomGroupBox>
</Grid>
</Window>
However, when I launch this form, I see the border of my custom control but not the content (2 TextBlock's):
I've re-read many manuals and articles related to this topic, but still can't figure out why ContentControl in my ControlTemplate does not display the specified content. How to solve my problem?
Try using ContentPresenter instead of ContentControl in your template:
<ContentPresenter />
By default, ContentPresenter finds the Content property of its templated parent and displays whatever it finds there. You could change the name of the property it looks for by changing its ContentSource value...
<ContentPresenter ContentSource="FooBar" />
...but since you're inheriting from ContentControl, the default is probably what you want.

external xaml resource not found by designer when referenced from control template

I have external library libccc with its own resources defined like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ccc="clr-namespace:libccc"
>
<ccc:BooleanToHiddenVisibilityConverter x:Key="BooleanToHiddenVisibilityConverter" />
</ResourceDictionary>
In my main project I include it using ResourceDictionary.MergedDictionaries in main app.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/libccc;component/Resources/Converters.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Now my problem is that when I reference that resource from Control template only like this:
<window style="{StaticResource MyDialog}">
</window>
where style is defined in application like this:
<ResourceDictionary>
<Style x:Key="MyDialog" TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid>
<Label HorizontalAlignment="Center" Content="{Binding UpdateResultDescription}" Visibility="{Binding UpdateEnded, Converter={StaticResource BooleanToHiddenVisibilityConverter}, FallbackValue=Hidden}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary
VisualStudio Designer throws exception:
Exception: Cannot find resource named 'BooleanToHiddenVisibilityConverter'. Resource names are case sensitive.
My application works as expected, but designer throws exception. When I reference my libccc in other windows that do not use control template then designer works fine.
Anyone can give me a hint what can I change to make designer work?

How to create a dynamically changeable style with WPF in external library?

I am trying to make a library (with WPF) that will contain some of my basic templates for windows , buttons and some another new costume controls and templates for later use in projects .
I am still new to WPF . I understood that i should create a new ResourceDictionary in my external library and put there all my styles and their dynamic variables . And later make a MergedResourceDictionary in my main application project that will give me access to use my usual styles and controls .
Well i success to create a basic experimental style with a template which uses two variables as DynamicResource , Just for testing i made a <Brush x:Key="brush_back_standard">RoyalBlue</Brush> . This is used for regular back coloring . Then i declared to use this brush dynamically in the style itself : <Grid Background="{DynamicResource brush_back_standard}">, And It works well .
My problem begins when i am trying to change the brush value a runtime : Style.Resources[ "brush_back_standard" ] = Brushes.Aqua;. To simulate the case that the user will change the theme in the settings of the application later at runtime . So that didn't work at all , and i got the exception : ResourceDictionary is read-only and cannot be modified. . So if it's really readonly then it's sort of useless to me because the user cannot change the template at runtime . I need to find some way to let the user change anything in the window template at run time .
Full style code (external library) :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
<Style x:Key="window_standard"
TargetType="{x:Type Window}">
<Style.Resources>
<system:Double x:Key="thickness_shadow">10</system:Double>
<Brush x:Key="brush_back_standard">RoyalBlue</Brush>
</Style.Resources>
<Setter Property="WindowStyle"
Value="None" />
<Setter Property="AllowsTransparency"
Value="True" />
<Setter Property="BorderThickness"
Value="{DynamicResource thickness_shadow}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid Background="{DynamicResource brush_back_standard}">
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
<ResizeGrip x:Name="WindowResizeGrip"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Visibility="Collapsed"
IsTabStop="false" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ResizeMode"
Value="CanResizeWithGrip">
<Setter TargetName="WindowResizeGrip"
Property="Visibility"
Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Accessing the library in my main application project :
<Application x:Class="diamond.sandbox.executer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="window_main.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/diamond.core;component/xaml/standard.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
The window_main.xaml which is magically affected by the style :
<Window x:Class="diamond.sandbox.window_main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="window_main" Height="250" Width="500"
Style="{DynamicResource window_standard}"
WindowStartupLocation="CenterScreen"
Loaded="initialise">
Initialise method (After window_main is loaded) :
private void initialise( object p_sender , RoutedEventArgs p_args )
{
Style.Resources[ "brush_back_standard" ] = Brushes.Aqua;
}
Well, you can't modify a Style (not even its Resources) at all because it has been frozen. The Style is a Freezable, and will be frozen by WPF when added to a ResourceDictionary. Instead, you should just modify the Window's Resources:
private void initialise( object p_sender , RoutedEventArgs p_args )
{
Resources[ "brush_back_standard" ] = Brushes.Aqua;
}

Access `DependencyProperty` via XAML and evaluate it?

I just created a DependencyProperty for my custom button.
The property is called IsChecked.
If IsChecked == true my button shall change its background color to something else and keep this color until IsChecked == false.
Here is my DependencyProperty:
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(MainMenuButton), new PropertyMetadata(false));
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
Next I have a ControlTemplate for this button:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ControlTemplate x:Key="MainMenuButtonStyle" TargetType="{x:Type UserControl}">
<ControlTemplate.Resources>
/* Some storyboards */
</ControlTemplate.Resources>
<Grid x:Name="grid">
<Grid.Background>
<SolidColorBrush Color="{DynamicResource MainUI_MainMenuButtonBackground}"/>
</Grid.Background>
</Grid>
<ControlTemplate.Triggers>
/* Some triggers */
</ControlTemplate.Triggers>
</ControlTemplate>
My problem is now how I can access IsChecked and based on the current value of it change the background of grid? Haven't done that before only tried it some time ago and totally failed.
Thanks in advance :)
Edit:
Here is the UserControl aswell:
<UserControl
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="IFCSMainInterface.MainMenuButton"
x:Name="UserControl"
d:DesignWidth="640" d:DesignHeight="480" Width="272" Height="110" Template="{DynamicResource MainMenuButtonStyle}">
<Grid x:Name="LayoutRoot"/>
I think the problem is here:
<ControlTemplate x:Key="MainMenuButtonStyle" TargetType="{x:Type UserControl}">
You must set the correct type in order to use its dependency property.
Write in your ResourceDictionary the namespace of the class, and put your type correctly in control template, eg:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:ProjectName.NameSpace">
<ControlTemplate TargetType="my:MainMenuButton" x:Key="MainMenuButtonStyle">
<!-- ... -->
</ControlTemplate>
</ResourceDictionary>
Edit (now that was explained):
You're trying to define a template in xaml own control
That does not seem quite right to do, I suggest looking for other approaches, such as creating a control that uses a Generic.xaml
( http://utahdnug.org/blogs/xamlcoder/archive/2007/12/13/building-custom-template-able-wpf-controls.aspx )
but if you want to use the dependency properties (the way you're doing) you can try the following code (for example):
<UserControl x:Class="SamplesStack.Controls.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:SamplesStack.Controls">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid x:Name="LayoutRoot">
<ContentPresenter />
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsChecked}" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="Red"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Template>
This will make your control work as expected. Though not think very cool use DataTrigger.

wpf silverlight multi-targeting ResourceDictionary

I'm writing some multi-targeting application (.net 4.0). I have problems with ResourceDictionay.
Scenario:
Create WPF CustomControlLibrary - name it "WpfLib", default Namespace "test"
In WpfLib create UserControl - name it "uc"
<UserControl x:Class="test.uc"
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">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="res.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Button Style="{StaticResource bStyle}" Content="Button" Height="23" Width="75" />
</Grid>
</UserControl>
Code for "res.xaml"
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="bStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red" />
</Style>
</ResourceDictionary>
Everything is great now....Button is Red
Now lets add new Project Silverlight Application and name it "SlApp" (Silverlight 5)(namespace "test")
Lets add "uc" from "WpfLib" as link("uc.xaml" "uc.xaml.cs" ).
Create new ResourceDictionary in "SlApp" and name it res.xaml like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="bStyle" TargetType="Button">
<Setter Property="Background" Value="Blue" />
</Style>
</ResourceDictionary>
New ResourceDictionary has TargetType="Button" because x:Type is not supported in SilverLight. Background is set to color Blue not red.
And here starts the problem.
How do i make it work? Control uc displays error on merging(in Silverlight version). I need different ResourceDictionary on Wpf and Silverlight version of usercontrol. ClassLibrary doesn't support app.xaml and i can't use default style.

Categories