コントロール自身にValidation機能を持たせたユーザコントロールの例
開発環境:VisualStudio2010 Silverlight4

最近SilverLight4のアプリを開発してるのですが、日本語情報はすくないですねぇ。しかたなく英文と格闘する毎日を送っています。
情報をもらってばかりいるのは気が引けますので、少しづつですが私も情報を発信していきます。ほんとうは半年後の自分のためでもあるんでしけどね。まずは出来立てのユーザコントロールからどうぞ。

使用している技術内容

  1. ユーザコントロール
  2. Varidation
  3. Entity
  4. 依存関係プロパティ
  5. Bindをコードで記述

などにご注目ください。ちょっとてんこもりすますね^^;
直接入力やElementバインディングでも使用できることを確認しました。データバインディングのテストはしてませんが、たぶん大丈夫でしょう。

TestControl1.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Data;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel.DomainServices.Client;

namespace SilverlightApplication1.Controls
{
    /// <summary>
    /// 内部にエンティティデータを持つユーザコントロールの例
    /// コントロール単独でVlidation機能を実装。
    /// Emptyと1以外のデータはエラーになる。
    /// 2011/02/22 Visualstudio 2010 + Silverlight4
    /// </summary>
    public partial class testControl1 : UserControl
    {

        public testControl1() {
            InitializeComponent();
            //InDataはXAML側でリソースとして定義してある。
            InData = new TestControlEntity();
            InData.PropertyChanged += new PropertyChangedEventHandler(InData_PropertyChanged);
            //デザインモードの時はバインドしない。
            //(コードによるBindingの例)
            if (!DesignerProperties.IsInDesignTool) {
                Binding b = new Binding();
                b.Source = InData;
                b.Path = new PropertyPath("InText");
                b.Mode = BindingMode.TwoWay;
                b.NotifyOnValidationError = true;
                b.ValidatesOnDataErrors = true;
                b.ValidatesOnExceptions = true;
                b.ValidatesOnNotifyDataErrors=true;
                textBox1.SetBinding(TextBox.TextProperty,b);
            }
        }

        void InData_PropertyChanged(object sender, PropertyChangedEventArgs e) {
            if (e.PropertyName == "Text") {
                this.Text = ((TestControlEntity)sender).InText;
            }
        }

        #region 依存関係プロパティ(Text) 黄金パターン^^V
        //-----------------------------------------------------------------------------------
        public readonly static DependencyProperty TextProperty =
               DependencyProperty.Register("Text", typeof(string), typeof(testControl1),
               new PropertyMetadata("",
                   new PropertyChangedCallback(testControl1.OnTextChangedStatic)));

        private static void OnTextChangedStatic(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            ((testControl1)d).OnTextChanged(e);
        }

        private void OnTextChanged(DependencyPropertyChangedEventArgs e) {
            //InData.InText = e.NewValue.ToString(); //<--これはダメ ElementBindingの例で落ちる(右の例)
            if (textBox1 != null) {
                textBox1.Text = e.NewValue.ToString();

            }
        }

        [Category("共通")]
        public object Text {
            set { SetValue(TextProperty, value); }
            get { return GetValue(TextProperty); }
        }
        //-----------------------------------------------------------------------------------
        #endregion

    }
// //////////////////////////////////////////////////////////////////////////////////////////////
    /// <summary>
    /// ユーザコントロール内部で使用するEntity
    /// </summary>
    public class TestControlEntity : INotifyPropertyChanged
    {
        public TestControlEntity(){}
        private string _InText="";
        public string InText {
            set {
                //内部データとコントロールの表示を一致させる場合はこっちを使う
                //正しくない値でもセットして通知
                //if (_InText == value) { return; }
                //_InText = value;
                //OnPropertyChanged("Text");

                if (!String.IsNullOrEmpty(value) && value != "1") {
                        throw new ArgumentException("TextはEmptyまたは1でなければなりません。:["+value.ToString()+"]");
                }

                //正しい値なのでセットして通知
                _InText = value;
                OnPropertyChanged("Text");
            }

            get {
                return _InText;
            }

        }

        #region INotifyPropertyChanged メンバー

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string Name) {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(Name));
            }
        }
        #endregion
    }
}

testControl1.xaml
使用するには
xmlns:Local=”clr-namespace:SilverlightApplication1.Controls”
あたりを修正しないといけませんね。

<UserControl x:Class="SilverlightApplication1.Controls.testControl1"
    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"
             xmlns:Local="clr-namespace:SilverlightApplication1.Controls"
    d:DesignHeight="57" d:DesignWidth="226">
    <UserControl.Resources>
        <Local:TestControlEntity x:Name="InData" />
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="#FFCDF2DB">

        <TextBlock Height="21" HorizontalAlignment="Stretch" Name="textBlock1" Text="Emptyと1以外はエラーとなるTextBox" VerticalAlignment="Stretch" TextWrapping="Wrap" Margin="0,0,0,36" Padding="2" />
        <TextBox Height="24" Margin="19,23,23,10" Name="textBox1" />
    </Grid>
</UserControl>

実行例 Xaml
下記のコードは使用例です。実際に実行する時は、このユーザコントロールを使用するページを作成してみてください。
下記のカット&ペーストでは動きませんよ。

<navigation:Page x:Class="SilverlightApplication1.Views.Page4"
           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"
           xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           d:DesignWidth="640" d:DesignHeight="480"
           Title="Page4 Page" xmlns:my="clr-namespace:SilverlightApplication1.Controls">
    <Grid x:Name="LayoutRoot">
        <my:testControl1 HorizontalAlignment="Left" Margin="79,142,0,0" x:Name="testControl11" VerticalAlignment="Top" TabIndex="2" />
        <TextBox Height="24" HorizontalAlignment="Left" Margin="79,100,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" TabIndex="1" Text="ダミーパーキング場所" />
        <TextBox Height="24" HorizontalAlignment="Left" Margin="79,217,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" TabIndex="3" Text="ダミーパーキング場所" />

        <my:testControl1 HorizontalAlignment="Left" Margin="439,142,0,0" x:Name="testControl12" VerticalAlignment="Top" TabIndex="5" Text="{Binding Path=Text, ElementName=textBox3}" />
        <TextBox Height="24" HorizontalAlignment="Left" Margin="509,100,0,0" Name="textBox3" VerticalAlignment="Top" Width="52" TabIndex="4" />
        <TextBox Height="24" HorizontalAlignment="Left" Margin="444,217,0,0" Name="textBox4" VerticalAlignment="Top" Width="120" TabIndex="6" Text="ダミーパーキング場所" />
        <TextBlock Height="23" HorizontalAlignment="Left" Margin="380,100,0,0" Name="textBlock1" Text="Elementバインディング" VerticalAlignment="Top" />
    </Grid>
</navigation:Page>