I have a custom UserControl
which is basically just a fancy container that has a title and some contents:
And this is how I use it in my XAML:
<local:MDCard Header="Some Title">
<Grid>
...
...
</Grid>
</local:MDCard>
The problem is that in design time (before running the code) this is what I see in the graphical XAML editor:
Notice that the title is not showing.
And this is the source code of my UserControl
:
<UserControl x:Class="HealthAndWellBeing.MDCard"
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:local="clr-namespace:HealthAndWellBeing"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300"
x:Name="self">
<UserControl.Template>
<ControlTemplate TargetType="{x:Type UserControl}">
<Grid>
<Grid>
<Grid.Effect>
<DropShadowEffect Direction="270" ShadowDepth="1" Opacity="0.2" BlurRadius="2"/>
</Grid.Effect>
<Grid>
<Grid.Effect>
<DropShadowEffect Direction="270" ShadowDepth="0" Opacity="0.12" BlurRadius="8"/>
</Grid.Effect>
<Grid>
<Grid.Effect>
<DropShadowEffect Direction="270" ShadowDepth="1" Opacity="0.14"/>
</Grid.Effect>
<Border Background="#FFFAFAFA" CornerRadius="2"/>
</Grid>
</Grid>
</Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderThickness="0,0,0,1" BorderBrush="#19000000">
<Label FontWeight="Bold" Foreground="#FF616161" Margin="10,10,10,10">
<ContentPresenter Content="{Binding Header}"/>
</Label>
</Border>
<ContentPresenter Grid.Row="1"/>
</Grid>
</Grid>
</ControlTemplate>
</UserControl.Template>
And this is my code-behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace HealthAndWellBeing
{
/// <summary>
/// Interaction logic for MDCard.xaml
/// </summary>
public partial class MDCard : UserControl, INotifyPropertyChanged
{
public MDCard()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyChange(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(MDCard), new PropertyMetadata("Title"));
}
}
So Why is it that when I change the text of a Button
it can be seen in the graphical XAML editor instantly, but changing the Header
of my custom UserControl
can only be seen at run time?
In essence, changing the Binding-Signature of your Label from
<Label FontWeight="Bold" Foreground="#FF616161" Margin="10,10,10,10">
<ContentPresenter Content="{Binding Header}"/>
</Label>
to
<Label FontWeight="Bold" Foreground="#FF616161" Margin="10,10,10,10">
<ContentPresenter Content="{Binding Header, RelativeSource={RelativeSource TemplatedParent}}"/>
</Label>
should / could solve the issue.
After all you are not trying to resolve to a property Header
of the ControlTemplate
you are giving to a UserControl
, but to a Descendant of a UserControl
class that has a DependencyProperty
called Header
.
This is why you should bind to the TemplatedParent, i.e. the actual UserControl
descendant.
In the case of a CustomControl you use the compile-time binding TemplateBinding
, since you are templating this specific class.
With UserControls
however you use Binding
s, which are resolved at runtime via System.Reflection
. That's why you are supposed to tell it to look for a specific parent if it is not a property of that specific class. In this case the TemplatedParent
.
A better explanation between Binding vs TemplatedBinding however can be found here.
I can only assume that the "real" WPF runtime libraries will simply help you resolve the actual DependencyProperty - the blend (VS designer) ones won't.