none
エラー発生時のControlTemplateでの表示に関して RRS feed

  • 質問

  • WPF+C#+Livetを使用している環境での質問になります。


    プログラミングは初心者で、書籍、ネットで勉強しながら簡単な画面を構築していますが、以下の点で躓きました。
    お手数ですが、どなたかに解決策等をご助言頂けると有難いです。

    MainWindow.xamlは別ResourceDictionaryファイルからWindowのControlTemplateを取得しています。

    MainWindow.xaml内のtextboxに別ResourceDictionaryに記載したエラー表示用のControlTemplateを利用してViewModel側でのエラー発生時にその内容を表示させようとしています。

    ところが、WindowのControlTemplateを使用した画面ではエラーの表示が行われず、
    WindowのControlTemplateを使用しないようにすると、エラーが表示されます。

    最終形はWindowのControlTemplateもエラー表示用のControlTemplateも、両方を使用して画面を構築したいと考えていますが、どうすればよろしいでしょうか?


    ●Dictionary2.xaml:WindowのControlTemplate

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
                        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf">
    
    
        <Style x:Key="DefaultWindowStyle" TargetType="Window">
            <Setter Property="Width" Value="1240"/>
            <Setter Property="Height" Value="800"/>
            <Setter Property="Title" Value="○●システム"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Window">
                        <Border Name="RootElement">
                            <Border.Background>
                                <SolidColorBrush x:Name="BorderBrush" Color="White"/>
                            </Border.Background>
                            <Grid Margin="15">
                                <Grid.RowDefinitions>
                                    <!-- メインタイトル、ログインユーザ等 -->
                                    <RowDefinition Height="50"/>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="30"/>
                                </Grid.RowDefinitions>
    
                                <Grid  Grid.Row="0">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="250" />
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="150" />
                                        <ColumnDefinition Width="105" />
                                    </Grid.ColumnDefinitions>
    
                                    <Border Grid.Column="0">
                                        <Border.Background>
                                            <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.GradientInactiveCaptionColorKey}}"/>
                                        </Border.Background>
                                    </Border>
    
                                    <Border Grid.Column="1">
                                        <Border.Background>
                                            <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.HighlightColorKey}}"/>
                                        </Border.Background>
                                        <StackPanel Grid.Column="1" Margin="5" HorizontalAlignment="Center" x:Name="MainTitle">
                                            <TextBlock Text="画面名" FontSize="25" FontWeight="Bold">
                                                <TextBlock.Foreground>
                                                    <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.MenuColorKey}}"/>
                                                </TextBlock.Foreground>
                                            </TextBlock>
                                        </StackPanel>
                                    </Border>
                                    <Border Grid.Column="2" BorderThickness="1,1,0,1">
                                        <Border.Background>
                                            <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.GradientInactiveCaptionColorKey}}"/>
                                        </Border.Background>
                                        <StackPanel Grid.Column="2" Margin="5" HorizontalAlignment="Left" Orientation="Vertical">
                                        </StackPanel>
                                    </Border>
                                    <Border Grid.Column="3" BorderThickness="0,1,1,1">
                                        <Border.Background>
                                            <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.GradientInactiveCaptionColorKey}}"/>
                                        </Border.Background>
                                        <StackPanel Grid.Column="2" Margin="0">
                                        </StackPanel>
                                    </Border>
                                </Grid>
    
                                <ContentPresenter Grid.Row="1" Margin="0, 0"/>
    
                                <Border Grid.Row="4" Background="Gray">
                                    <StackPanel Grid.Row="4">
                                    </StackPanel>
                                </Border>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

    ●Dictionary3.xaml:エラーテンプレートのControlTemplate

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        
        <ControlTemplate x:Key="ErrorTemplate">
            <DockPanel>
                <ItemsControl DockPanel.Dock="Right" Margin="5,0"
                                  ItemsSource="{Binding ElementName=adornedElement, Path=AdornedElement.(Validation.Errors)}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding ErrorContent}" Foreground="Red"/>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
    
                <Border BorderBrush="Red" BorderThickness="1"
                            Width="{Binding ElementName=adornedElement, Path=ActualWidth}"
                            Height="{Binding ElementName=adornedElement, Path=ActualHeight}">
                    <AdornedElementPlaceholder Name="adornedElement"/>
                </Border>
            </DockPanel>
        </ControlTemplate>
    ●MainWindow.xaml

    <Window x:Class="LivetWPFApplication1.Views.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
            xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
            xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
            xmlns:v="clr-namespace:LivetWPFApplication1.Views"
            xmlns:vm="clr-namespace:LivetWPFApplication1.ViewModels">
    
        <Window.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="/Dictionary2.xaml"/>
                    <ResourceDictionary Source="/Dictionary3.xaml"/>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Window.Resources>
        <Window.Style>
            <Binding Source="{StaticResource DefaultWindowStyle}"/>
        </Window.Style>
    
        <!--<Window.DataContext>
            <vm:MainWindowViewModel/>
        </Window.DataContext>-->
        
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="ContentRendered">
                <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
            </i:EventTrigger>
            <i:EventTrigger EventName="Closed">
                <l:DataContextDisposeAction/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
    
            <Border Grid.Row="0">
                <StackPanel Grid.Row="0" Orientation="Vertical" VerticalAlignment="Center">
                    <TextBox Width="40"
                         Text="{Binding txtItem,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,ValidatesOnNotifyDataErrors=True}"
                         Validation.ErrorTemplate="{StaticResource ErrorTemplate}">
                    </TextBox>
                    <Button Content="dummy" Width="40"/>
                </StackPanel>
            </Border>
        </Grid>
    </Window>
    ※以下の3行をコメントアウトすると、エラー内容は正しく表示されます。
        <Window.Style>
            <Binding Source="{StaticResource DefaultWindowStyle}"/>
        </Window.Style>


    ●MainWindow.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace LivetWPFApplication1.Views
    {
    
        /// <summary>
        /// MainWindow.xaml の相互作用ロジック
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext = new LivetWPFApplication1.ViewModels.MainWindowViewModel();
    
            }
        }
    }
    ●MainWindowViewModel.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    
    using Livet;
    using Livet.Commands;
    using Livet.Messaging;
    using Livet.Messaging.IO;
    using Livet.EventListeners;
    using Livet.Messaging.Windows;
    
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Windows.Media;
    
    
    using LivetWPFApplication1.Models;
    
    namespace LivetWPFApplication1.ViewModels
    {
        public class MainWindowViewModel : ViewModel, INotifyDataErrorInfo
        {
            private Dictionary<string, string[]> Errors = new Dictionary<string, string[]>();
            public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    
            public void Initialize()
            {
            }
    
    
            #region MyProperty変更通知プロパティ
            private int _txtItem;
    
            public int txtItem
            {
                get
                { return _txtItem; }
                set
                { 
                    if (_txtItem == value)
                        return;
                    _txtItem = value;
                    var _value = value.ToString();
                    string[] _ErrorInfo = Validate(_value);
                    Errors["txtItem"] = _ErrorInfo;
                    RaiseErrorsChanged("txtItem");
    
                    RaisePropertyChanged();
                }
            }
            #endregion
    
            private List<string> _ErrorInfo = new List<string>();
            public string[] Validate(object pValue)
            {
                var inputValue = pValue as string;
                if (inputValue != null)
                {
                    _ErrorInfo.Add("値が入っていない");
                }
                int parsedValue = 0;
                if (int.TryParse(inputValue, out parsedValue))
                {
                    _ErrorInfo.Add("値が数値ではない");
                }
                if (parsedValue % 2 != 0)
                {
                    _ErrorInfo.Add("値が偶数ではない");
                }
                string[] _ErrorInfoResult = _ErrorInfo.ToArray();
                return _ErrorInfoResult;
            }
    
            protected virtual void RaiseErrorsChanged([CallerMemberName]string propertyName = "")
            {
                var h = this.ErrorsChanged;
                if (h != null)
                {
                    h(this, new DataErrorsChangedEventArgs(propertyName));
                }
            }
    
            // エラーメッセージを取得する
            public System.Collections.IEnumerable GetErrors(string propertyName)
            {
                if (string.IsNullOrWhiteSpace(propertyName)) return null;
                if (!Errors.ContainsKey(propertyName)) return null;
                return Errors[propertyName];
            }
    
            // エラーの有無
            public bool HasErrors
            {
                get { return Errors.Values.Any(x => x != null); }
            }
    
    
    
        }
    }


    2015年10月15日 14:50

回答

  • Adornerを表示するためのレイヤーが表示できなくなってます。
    AdornerDecoratorをContentPresenterよりも外側に配置してみてください。

    <ControlTemplate TargetType="Window">
        <AdornerDecorator>
            <Border Name="RootElement">
                <!-- 省略 -->
            </Border>
        </AdornerDecorator>
    </ControlTemplate>



    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2015年10月15日 23:08

すべての返信

  • Adornerを表示するためのレイヤーが表示できなくなってます。
    AdornerDecoratorをContentPresenterよりも外側に配置してみてください。

    <ControlTemplate TargetType="Window">
        <AdornerDecorator>
            <Border Name="RootElement">
                <!-- 省略 -->
            </Border>
        </AdornerDecorator>
    </ControlTemplate>



    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2015年10月15日 23:08
  • gekka様

    ご丁寧にありがとうございました。

    無事に、あっさりと、解決することができました。

    AdornerDecorator、まだまだ勉強することがたくさんありそうです。

    2015年10月16日 12:38