none
【MVVM】Validationの結果が画面に反映されない RRS feed

  • 質問

  • いつも御世話になっております。
    山田です。

    MVVMを利用しております。
    Validation のことで質問させて頂きます。

    Windows が開かれるタイミングと値がバインディングされるタイミングでValidationを掛けております。
    Button の Command利用して、下記のUserControlを呼び出し、Windowsを開いております。

    開かれるタイミングで、Validationが実行され、errors[propertyName] にもエラーが入っているのですが、
    呼び出し方によっては、結果が画面に反映されずに、枠に赤線がでないときがあります。

    対象のページを、TestAとします。
    作りとして、下記の場合に、起動時にValidationの結果が画面に反映しませんでした。

    【赤線が表示されない場合】
    1. ベースなるWindowから、Button 経由してWindowAを開く
    2. WindowAのButton経由から、TestAを開く
     (このときに、Validationは実行されているが、画面に赤線が表示されない)

    【赤線が表示される場合】
    1. ベースなるWindowから、Button 経由してTestAを開く
     (このときに、Validationは実行されているが、画面に赤線が表示される)


    原因が特定の仕方すらわからなく、手詰まりになり投稿させていただきました。
    お手数をおかけしますが、アドバイス宜しくお願い致します。



    ■Test.xaml
    <UserControl x:Class="Test.Views.Env.BuildingEditView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="88" Width="292">
        <Grid>
        	<Grid.ColumnDefinitions>
        		<ColumnDefinition Width="65"/>
        		<ColumnDefinition Width="0.79*"/>
        	</Grid.ColumnDefinitions>
        	<Grid.RowDefinitions>
        		<RowDefinition Height="40"/>
        		<RowDefinition Height="44"/>
        	</Grid.RowDefinitions>
        	<TextBox
                Margin="8,0,0,0"
                TextWrapping="Wrap"
                Grid.Column="1"
                HorizontalAlignment="Left"
                VerticalAlignment="Center"
                Width="200" Height="22.5"
                Text="{Binding BuildingName,
                NotifyOnValidationError=True,
                ValidatesOnDataErrors=True
                }"/>
        	<TextBlock Margin="0" Text="グループ名" TextWrapping="Wrap" HorizontalAlignment="Right" VerticalAlignment="Center"/>
        	<Button Margin="0" Content="保存(_S)" Grid.Row="1" Width="75" Height="22.5" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.ColumnSpan="2" Command="{Binding SaveCommand}"/>
                
        </Grid>
    </UserControl>

    ■C#
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Seasar.Quill;
    using Test.Model.Env;
    using Logic.Service;
    using Logic.DBFlute.ExEntity;
    using System.Windows.Input;
    using System.Windows;
    using System.ComponentModel;
    
    namespace Test.ViewModels.Env
    {
        public class BuildingEditViewModel : ViewModelBase, IDataErrorInfo
        {
            protected IBuildingService buildingService;
            
            private BuildingDto dto;
    
            public BuildingEditViewModel(BuildingDto dto)
            {
                this.dto = dto;
                QuillInjector.GetInstance().Inject(this);
                BuildingName = dto.BuildingName;
            }
    
            #region モデル
            public int? BuildingId
            {
                get { return dto.BuildingId; }
                set { dto.BuildingId = value; }
            }
    
            public string BuildingName
            {
                get { return dto.BuildingName; }
                set {
                    if (value == null)
                    {
                        SetError("BuildingName", "グループ名を入力してください。");
                    }
                    else
                    {
                        ClearError("BuildingName");
                    }
                    dto.BuildingName = value;
                    OnPropertyChanged("BuildingName");
                }
            }
    
            #endregion
    
            #region コマンド
            RelayCommand saveCommand;
            public ICommand SaveCommand
            {
                get
                {
                    if (saveCommand == null)
                    {
                        saveCommand = new RelayCommand(
                            param =>
                            {
                                if (IsCheck() == true)
                                {
                                    Save();
                                    EventHandler handler = RequestClose;
                                    if (handler != null)
                                        handler(this, EventArgs.Empty);
                                }
                            }
                        );
                    }
                    return saveCommand;
                }
    
            }
    
            public event EventHandler RequestClose;
    
            RelayCommand closeCommand;
            public ICommand CloseCommand
            {
                get
                {
                    if (closeCommand == null)
                    {
                        closeCommand = new RelayCommand(
                            param =>
                            {
                                EventHandler handler = this.RequestClose;
                                if (handler != null)
                                    handler(this, EventArgs.Empty);
                            }
                        );
                    }
                    return closeCommand;
                }
            }
    
    
            #endregion
    
            #region 実行メソッド
    
            private bool IsCheck()
            {
    
                if (string.IsNullOrEmpty(BuildingName))
                {
                    MessageBox.Show("グループ名を入力してください。");
                    return false;
                }
                return true;
            }
    
            private void Save()
            {
                Y11Building building = new Y11Building();
                building.BuildingId = dto.BuildingId;
                building.BuildingName = dto.BuildingName;
                buildingService.ExecUpdate(building);
            }
            #endregion
    
            #region IDataErrorInfo メンバ
    
            string IDataErrorInfo.Error
            {
                get { return null; }
            }
    
            string IDataErrorInfo.this[string columnName]
            {
                get
                {
                    string str = GetError(columnName);
                    if (str != null)
                    {
                        return str;
                    }
                    return null;
                }
            }
    
            #endregion
    
    
            #region 検証エラー操作用API
            private Dictionary<string, string> _errors = new Dictionary<string, string>();
    
            /// <summary>   
            /// 指定したプロパティにエラー情報をセットする   
            /// </summary>   
            /// <param name="propertyName"></param>   
            /// <param name="error"></param>   
            protected void SetError(string propertyName, string error)
            {
                _errors[propertyName] = error;
            }
    
            /// <summary>   
            /// 指定したプロパティのエラー情報を消去する   
            /// </summary>   
            /// <param name="propertyName"></param>   
            protected void ClearError(string propertyName)
            {
                if (!_errors.ContainsKey(propertyName))
                {
                    return;
                }
                _errors.Remove(propertyName);
            }
    
            /// <summary>   
            /// 指定したプロパティのエラーを取得する   
            /// </summary>   
            /// <param name="propertyName"></param>   
            /// <returns></returns>   
            protected string GetError(string propertyName)
            {
                string error = null;
                _errors.TryGetValue(propertyName, out error);
                return error;
            }
    
            /// <summary>   
            /// 現在エラーがあるプロパティ名の配列を取得する   
            /// </summary>   
            /// <returns></returns>   
            protected string[] GetErrorPropertyNames()
            {
                return _errors.Keys.ToArray();
            }
    
            /// <summary>   
            /// エラーがあるかどうか確認する。エラーがある場合はtrueを返す。   
            /// </summary>   
            /// <returns></returns>   
            public bool HasError()
            {
                return _errors.Count != 0;
            }
            #endregion  
    
        }
    }
    

    2009年9月12日 8:26

回答

  • Windows 7, Vista sp1では両方とも最初から赤枠で表示されましたが、Windows Xp sp3ではa_山田さんと全く同じ現象になりました。Windows Xpに関係する問題かもしれません。だとすると私にとっても問題になりそうです。もう少し調べてみて解決できなければコネクトに報告してみてはいかがでしょうか?

    Visual Studio & .NET Framework
    https://connect.microsoft.com/VisualStudioJapan
    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク a_山田 2009年9月24日 6:30
    2009年9月15日 0:24
    モデレータ

すべての返信

  • 通常そういうことは起こりません。
    Seasar などをはずしてシンプルな発生する例とその起動側(発生する方としない方)を見せてくれたらこちらでも再現試験ができると思いますが・・・

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年9月14日 6:36
  • ご回答ありがとうございます。

    Seasarなどをはずして、シンプルにして、
    一度、サンプルを作らせていただきました。
    お手数をおかけしますが、宜しくお願い致します。

    1.アプリを起動します。
    2.A Open をクリックし、Awindowを開く。
    3.B Open をクリック Bwindowsが開く ⇒ 赤い枠がでませんでした。

    1.アプリを起動します。
    2.B Direct をクリック、Bwindowsが開く => 赤い枠がでます。

    http://moon.s20.xrea.com/Sample.zip
    2009年9月14日 10:33
  • 私の環境では両方ともアカ枠が出ます。

    Windows 7 64bit
    Microsoft Visual Studio 2008
    Version 9.0.30729.4108 QFE
    Microsoft .NET Framework
    Version 3.5 SP1


    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年9月14日 11:42
  • えムナウ様、ありがとうございます。

    環境の問題かもしれないですね。

    私の利用している環境は、

    Windows XP 32bit Pro Sp3
    Microsoft Visutal Studio 2008 Version 9.0.30729.1 SP
    Microsfot .NET Framework Version 3.5 SP1

    でした。

    近くにあるマシーンでも試してみたいと思います。
    2009年9月14日 12:00
  • 他のマシーンでためさせていただきました。

    文字数オーバーでは、赤枠がでましたが、
    B Windowが開いたとには、赤枠になりませんでした。

    環境は、Windows XP 32Bit Pro Sp3
    Microsoft Visual Studio 2008 Version 9.0.21022.8 RTM
    Microsoft .NET Framwork Version 3.5. SP1

    です。

    また、プログラムを作成した環境でも、プロジェクトごと削除して、クリーンな状態にして再度ビルドしたら、
    同じ現象で、文字数オーバーでは、赤枠がでて、Window オープン時には、赤枠になりませんでした。
    2009年9月14日 12:12
  • Windows 7, Vista sp1では両方とも最初から赤枠で表示されましたが、Windows Xp sp3ではa_山田さんと全く同じ現象になりました。Windows Xpに関係する問題かもしれません。だとすると私にとっても問題になりそうです。もう少し調べてみて解決できなければコネクトに報告してみてはいかがでしょうか?

    Visual Studio & .NET Framework
    https://connect.microsoft.com/VisualStudioJapan
    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    • 回答としてマーク a_山田 2009年9月24日 6:30
    2009年9月15日 0:24
    モデレータ
  • trapemiya 様、ご回答ありがとうございます。

    Vista sp1でもためさせていただきました。Vista Sp1だと、trapemiyaさんと同様、初回起動時に、赤い枠が出ておりました。
    色々と変更して試してみましたが、結果としては上手くいきませんでした。

    一度、フィードバックしてみたいと思います。
    2009年9月15日 5:40