0
votes

Quick Overview

I've created a custom control "InputValuePage". I've registered a dependency property with this control named InputTitle. Binding within the User Control InputTitle to a textblock works great however I when using this custom control as a child in a frame or window I can't use a binding to set my dependency properties. Below is the code used for the InputTitle property.

Custom Control Class Code Behind :

public partial class InputValuePage : Page
{
public static readonly DependencyProperty InputTitleProperty  =
    DependencyProperty.Register("InputTitle", typeof(string), typeof(InputValuePage));

public string InputTitle
    {
        get { return (string)GetValue(InputTitleProperty); }
        set { SetValue(InputTitleProperty, value); }
    }

public InputValuePage()
    {
        InitializeComponent();
    }
}

Example Usage:

<Frame Grid.Row="2" 
           Grid.ColumnSpan="2"
           Grid.RowSpan="2"
           x:Name="DisFrame">
        <Frame.Content>
            <local:InputValuePage 
                                  InputMessage="This gets set in the control." 
                                  InputTitle="{Binding ElementName=DisFrame, Path=Name}" 
                                  HostWindow="{Binding ElementName=DemoWindow}">
            </local:InputValuePage>
        </Frame.Content>
    </Frame>

To clarify the three values set in the XAML are all dependency properties. Input Message and Title can successfully set when a string is provided however data bindings never actually set a value. What am I missing to allow for binding data?

1
Is the Name property of DisFrame set anywhere? What is DemoWindow? Note that element names are not valid across XAML files. - Clemens
The name "DisFrame" is set in the example usage block above. DemoWindow is the name assigned to the parent window hosting all of the controls including the frame shown in the example usage. I can do the same binding to a button's content or textblock's text with no problem, however, it doesn't work for the custom control - Dammer15
Specifying x:Name sets the name property. If I replace the custom control with a button and specify the exact same binding for the button's content property that I used for InputTitle shown above everything works as expected - Dammer15

1 Answers

1
votes

If you make a custom control, this works perfectly. A custom control inherits from Control. Your class inherits from Page.

I have tried it with the following code:

using System.Windows;
using System.Windows.Controls;

namespace WpfCustomControlLibrary1
{
  public class InputValuePage : Control
  {
    public static readonly DependencyProperty InputTitleProperty =
      DependencyProperty.Register ("InputTitle", typeof (string), typeof (InputValuePage));

    public string InputTitle
    {
      get { return (string)GetValue (InputTitleProperty); }
      set { SetValue (InputTitleProperty, value); }
    }

    static InputValuePage ( )
    {
      DefaultStyleKeyProperty.OverrideMetadata (typeof (InputValuePage), new FrameworkPropertyMetadata (typeof (InputValuePage)));
    }
  }
}

This is the ControlTemplate in my Generic.xaml file. Note that you can use TemplateBinding to access the property in the template.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfCustomControlLibrary1">
  <Style TargetType="{x:Type local:InputValuePage}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:InputValuePage}">
          <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">

            <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20" Text="{TemplateBinding InputTitle}"/>

          </Border>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

Visual Studio automatically generates a ControlTemplate when you create a custom control project.

In my test project, I wired the InputTitle property up to the contents of a TextBox.

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        xmlns:cc="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1"
        Title="MainWindow" Height="200" Width="200">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <TextBox Grid.Row="0" x:Name="TitleBox" Text="ABC"/>

    <Frame Grid.Row="1" x:Name="DisFrame">
      <Frame.Content>
        <cc:InputValuePage InputTitle="{Binding ElementName=TitleBox, Path=Text}"/>
      </Frame.Content>
    </Frame>

  </Grid>
</Window>

I'm pretty sure that this would also work with a UserControl, if you find that easier.

Evidently, it does not work with a Page.