CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

PropertyStatus in TextBox Style

rated by 0 users
Answered (Not Verified) This post has 0 verified answers | 9 Replies | 4 Followers

Top 100 Contributor
77 Posts
Russ Blair posted on Thu, May 20 2010 3:08 PM

I'm trying to create a WPF textbox style that incorporates PropertyStatus. This would have the benefit of not having to code the propertystatus control after every textbox on every form. I am unable to get it to work. I'm having difficulty with the template binding (I think). Here is my style source:

<!-- cslatextbox style -->

<Style x:Key="CslaTextBoxStyle" TargetType="{x:Type TextBox}">

  <Setter Property="Margin" Value="0,1,0,1"/>

  <Setter Property="Validation.ErrorTemplate">

    <Setter.Value>

      <ControlTemplate>

        <Grid>

          <Grid.ColumnDefinitions>

            <ColumnDefinition Width="*"/>

            <ColumnDefinition Width="Auto"/>

          </Grid.ColumnDefinitions>

          <AdornedElementPlaceholder Grid.Column="0" />

          <csla:PropertyStatus Grid.Column="1"

              Property="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=Text}"

              TargetControl="{Binding RelativeSource={RelativeSource TemplatedParent}}"/>

        </Grid>

      </ControlTemplate>

    </Setter.Value>

  </Setter>

  <Style.Triggers>

    <Trigger Property="IsReadOnly" Value="true">

      <Setter Property="Background" Value="lightyellow"/>

    </Trigger>

  </Style.Triggers>

</Style>

 

Here is the typical textbox Xaml:

<TextBox Grid.Column="1" Grid.Row="0" Name="CodeTextBox"

    Text="{Binding Code, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True,

    UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource CslaTextBoxStyle}"/>

 

Can anyone suggest a solution or explain why this can't be done.

Thanks

Russ

 

 

All Replies

Top 100 Contributor
71 Posts
dagware replied on Sun, May 23 2010 11:53 AM

First off, I know so little about all of this (I'm just learning WPF) that anything I say is probably wrong. But that's never stopped me before!

I think your PropertyStatus' Property binding should use TemplateBinding, not Binding. The way you have it now, it's bound to the contents of the Text property, not the Text binding source.

But I still can't figure out how to get the TargetControl binding to work correctly.

Dan

Top 100 Contributor
71 Posts
dagware replied on Sun, May 23 2010 12:10 PM

I was assuming there was an error in the TargetControl binding, because VS said it was missing a Path. Turns out this is a known bug, and can be ignored, or you can fix it by adding "Path=.".

Dan

Top 100 Contributor
77 Posts

Thanks for the ideas dagware. Unfortunately I am still unable to find the correct syntax to get this to work.

Top 100 Contributor
77 Posts

I have given up on using a style and I am now attempting to create a CslaTextBox UserControl. The goal is to replace several thousand of these:

<TextBlock Grid.Column="0" Grid.Row="0" Name="CodeTextBlock" Text="Code:" Style="{StaticResource TextBlockStyle}" />

<TextBox Grid.Column="1" Grid.Row="0" Name="CodeTextBox"

         Text="{Binding Code, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"

         Style="{StaticResource TextBoxStyle}"

         IsReadOnly="{Binding ElementName=CodePropertyStatus, Path=CanWrite, Converter={StaticResource invertBoolConverter}}"/>

<csla:PropertyStatus Grid.Column="2" Grid.Row="0" x:Name="CodePropertyStatus" Property="{Binding Path=Code}"/>

 

with these:

<TextBlock Grid.Column="0" Grid.Row="0" Name="CodeTextBlock" Text="Code:" Style="{StaticResource TextBlockStyle}" />

<controls:CslaTextBox Grid.Column="1" Grid.Row="0" x:Name="CodeTextBox" Text="{Binding Code}" />

 

The CslaTextBox UserControl will simply have a TextBox and a PropertyStatus control. Here is the XAML:

<UserControl x:Class="LossTrack.Controls.CslaTextBox" x:Name="cslaTextBox"

  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:csla="clr-namespace:Csla.Xaml;assembly=Csla.Xaml"

  mc:Ignorable="d"

  d:DesignHeight="23" d:DesignWidth="150">

 

  <UserControl.Resources>

    <csla:IdentityConverter x:Key="IdentityConverter" />

  </UserControl.Resources>

 

  <Grid x:Name="LayoutRoot">

    <Grid.ColumnDefinitions>

      <ColumnDefinition Width="*"/>

      <ColumnDefinition Width="Auto"/>

    </Grid.ColumnDefinitions>

   

    <TextBox Grid.Column="0" x:Name="textBox" IsEnabled="{Binding ElementName=propertyStatus, Path=CanWrite}" Margin="0,1,2,1"

             Text="{Binding ElementName=cslaTextBox, Path=Text, Converter={StaticResource IdentityConverter}, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>

   

    <csla:PropertyStatus Grid.Column="1" x:Name="propertyStatus"

                         Property="{Binding ElementName=cslaTextBox, Path=Text}"/>

 

  </Grid>

</UserControl>

 

Here is the CslaUserControl code behind:

using System;

using System.Windows;

using System.Windows.Controls;

 

namespace LossTrack.Controls

{

    public partial class CslaTextBox : UserControl

    {

        public CslaTextBox()

        {

            InitializeComponent();

        }

 

        public static readonly DependencyProperty TextProperty =

            DependencyProperty.Register("Text",

            typeof(string), typeof(CslaTextBox),

            new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(textChangedCallBack)));

 

        public string Text

        {

            get { return (string)GetValue(TextProperty); }

            set {   SetValue(TextProperty, value); }

        }

 

        static void textChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)

        {

            CslaTextBox cslaTextBox = (CslaTextBox)property;

            cslaTextBox.textBox.Text = (string)args.NewValue;

        }

    }

}

 

The TextBox Text binding appears to operate correctly in all respects. The problem is getting the correct XAML syntax for the clsa:PropertyStatus Property property.

Does anyone have any suggestions?

Thanks in advance

Russ.

Top 10 Contributor
9,425 Posts

PropertyStatus is a little special, in that it needs to get a reference to the actual underlying business object so it can add a handler for the object's PropertyChanged event. To do this, it takes the binding expression and uses it to get the underlying source object.

My guess is that what's happening here is that the underlying source object is the usercontrol, not the business object - but without using the debugger to walk through the PropertyStatus code it is hard to say for sure. That level of data binding infrastructure gets somewhat complex.

There is a GetRealSource() method in PropertyStatus that walks back through the dot notation of the Path to find the source. I'm guessing that code doesn't handle whatever is different about being inside a usercontrol.

Rocky

Top 500 Contributor
31 Posts
Turntwo replied on Fri, Oct 15 2010 12:19 AM

If anyone has figured this out, I'm trying to do the same thing, and having similar issues.  It would make things so much simpler (and cleaner) if this could work.

Top 500 Contributor
31 Posts
Suggested by Turntwo

OK, so I think I figured out a way to do it (haven't cleaned it up yet, but it appears to work).  Basically stole the technique from PropertyStatus.

The key part here is the SetSource method, which Binds the PropertyStatus.Property to the BOTextBox.Property binding - which then allows PropertyStatus to do it's thing.

The XAML:

<UserControl x:Class="JefBar.Core.WPF.BOTextBox"
             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:corewpf="clr-namespace:JefBar.Core.WPF"
 xmlns:csla="clr-namespace:Csla.Xaml;assembly=Csla.Xaml"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
 x:Name="boTextBox">
    <StackPanel
Orientation="Horizontal"
>
<TextBox
Name="patientNumber"
Text="{Binding ElementName=boTextBox, Path=Property, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"
IsEnabled="{Binding ElementName=propertyStatus, Path=CanWrite}"
Visibility="{Binding ElementName=propertyStatus, Path=CanRead, Converter={corewpf:BooleanToVisibilityConverter}}"
MinWidth="75" 
/>
<csla:PropertyStatus
x:Name="propertyStatus"
/>

</StackPanel>
</UserControl>

The Code Behind (interesting part):
using System.Windows;
using System.Windows.Data;
using Csla.Xaml;

namespace JefBar.Core.WPF
{
    /// <summary>
    /// Interaction logic for BOTextBox.xaml
    /// </summary>
    public partial class BOTextBox
    {
        /// <summary>
        /// Gets or sets the source business
        /// property to which this control is bound.
        /// </summary>
        public static readonly DependencyProperty PropertyProperty = DependencyProperty.Register(
          "Property",
          typeof(object),
          typeof(BOTextBox),
           new PropertyMetadata(new object(), (o, e) => ((BOTextBox) o).SetSource())
          );

        /// <summary>
        /// Gets or sets the source business
        /// property to which this control is bound.
        /// </summary>
        public object Property
        {
            get { return GetValue(PropertyProperty); }
            set { SetValue(PropertyProperty, value); }
        }

        /// <summary>
        /// Sets the source binding and updates status.
        /// </summary>
        private BindingExpression oldBinding;
        protected virtual void SetSource()
        {
            var binding = GetBindingBLOCKED EXPRESSION;
        }
    }
}


Top 75 Contributor
129 Posts
cds replied on Fri, Oct 15 2010 4:21 AM

This looks interesting - I'd like to see the full code - but it seems it hasn't come out properly. (See the BLOCKED EXPRESSION at the end).

Top 500 Contributor
31 Posts

Here is the source as an attachment, updated quite a bit since the original post (various templates and properties to control behavior).

Page 1 of 1 (10 items) | RSS

Copyright (c) 2006-2014 Marimer LLC. All rights reserved.
Email admin@lhotka.net for support.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems