views:

79

answers:

2

I was working on creating a reusable custom control (not a user control) in WPF. I created the XAML in the Themes/Generic.xaml file and I setup the "lookless" functionality in the control's CS file:

AddressField.cs

using ...;

namespace MyNamespace
{
    [TemplatePart(Name = AddressField.ElementAddress1TextBox,    Type = typeof(TextBox))]
    public class AddressField : Control
    {
        private const String ElementAddress1TextBox     = "PART_Address1TextBox";

        public AddressEntity Address
        {
            get { return (AddressEntity)GetValue(AddressProperty); }
            set { SetValue(AddressProperty, value); }
        }
        public static readonly DependencyProperty AddressProperty =
            DependencyProperty.Register("Address", typeof(AddressEntity), typeof(AddressField), new UIPropertyMetadata(null, new PropertyChangedCallback(OnAddressPropertyChangedCallback)));

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

Themes\Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyNamespace"
    >
    <Style TargetType="{x:Type local:AddressField}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:AddressField}">
                    <StackPanel>
                        <Grid x:Name="StandardView">
                            <Grid.Resources>
                                <Style TargetType="TextBlock">
                                    <Setter Property="Height" Value="17" />
                                    <Setter Property="Margin" Value="3,3,3,3" />
                                </Style>
                                <Style TargetType="TextBox">
                                    <Setter Property="Height" Value="23" />
                                    <Setter Property="Margin" Value="3,3,3,3" />
                                </Style>
                            </Grid.Resources>

                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="1*" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>

                            <!-- Address 1, Address2-->
                            <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="Address:" TextWrapping="NoWrap" />
                            <TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="8" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinWidth="300"
                                     x:Name="PART_Address1TextBox" Text="{Binding Path=Address1}" />
                        </Grid>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Form.xaml

<Window x:Class="NIC.BackOffice.Casino.RegistrationEntryForm"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:nic="clr-namespace:MyNamespace;assembly=MyStuff">

    <Canvas>
        <nic:AddressField Canvas.Left="10" Canvas.Top="10"
                          x:Name="OfficeAddressField" Address={Binding Path=OAddress} />
    </Canvas>
</Window>

Form.cs

using ...;

namespace MyNamespace
{
    public partial class Form : Window
    {
        public Form()
        {
            InitializeComponent();
            OAddress = new AddressEntity("1234 Testing Lane");
        }
        public AddressEntity OAddress { get; set; }
    }
}

UPDATED: The prior code is an update from my previous code (removed a lotta fluff just to get down to the ONE example). Though, for some reason Address (within OfficeAddressField) is never ever updated even though I set the binding of OAddress to the AddressField object.

A: 

You should consider raising an event when the address dp changes.

HTH

Avatar
+1  A: 

You don't need to refresh the DataContext. In fact, your control shouldn't be using it. Make Address a DependencyProperty and then use a TemplateBinding in your control's template:

<TextBox Text="{TemplateBinding Address.Address1}"/>

HTH,
Kent

Kent Boogaart
I'm not sure I'm making the correct changes in my code. So far I've changed: AddressEntity to inherit from a DependencyObject and Address1 as a DependencyProperty. Then, I turned Address (from within AddressField) into a DependencyProperty. These things don't help at all. No matter the mix and match of changes I have tried the "Address" property that resides in AddressField is never updated short of doing `myAddressField.Address = new Address(...);`. If I try to make it so that Address is databound, it just doesn't want to change. :-/
myermian
I ended up using `<Setter Property="DataContext" Value="{TemplateBinding Address}" /> which worked as well. But yes, TemplateBinding is what I was missing...
myermian