WP8 - ValidatesOnExceptions

时间:2013-07-15 17:00:06

标签: c# .net wpf windows-phone-8

我无法使用VS2012 for Windows Phone实现此功能。如果我创建一个包含属性ValidateOnExceptions = true的文本框并在setter中抛出异常,则不会捕获异常但只是在调试窗口中出现:

A first chance exception of type 'System.ArgumentException' occurred in PhoneApp1.DLL
An exception of type 'System.ArgumentException' occurred in PhoneApp1.DLL but was not handled in user code
System.Windows.Data Error: Cannot save value from target back to source. BindingExpression: Path='Thingy' DataItem='PhoneApp1.MyContext' (HashCode=38891250); target element is 'System.Windows.Controls.TextBox' (Name=''); target property is 'Text' (type 'System.String').. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: I said don't type 'foo'!
   at PhoneApp1.MyContext.set_Thingy(String value)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
   at System.Windows.CLRPropertyListener.set_Value(Object value)
   at System.Windows.PropertyAccessPathStep.set_Value(Object value)
   at System.Windows.Data.BindingExpression.UpdateValue().

我做了一个玩具示例来隔离问题 - 这是我的xaml:

<phone:PhoneApplicationPage
    x:Class="PhoneApp1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:my="clr-namespace:PhoneApp1;assembly=PhoneApp1"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">

        <TextBlock Text="Do NOT type 'foo' in this box"/>
      <TextBox Text="{Binding Thingy, Mode=TwoWay,  ValidatesOnExceptions=True}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

        </Grid>

    </Grid>

</phone:PhoneApplicationPage>

我的主页:

/* imports snipped..*/

namespace PhoneApp1 {

  public class MyContext {
    private String _thingy = String.Empty;
    public String Thingy {
      get {
        return _thingy;
      }
      set {
        if (value == "foo") {
          throw new ArgumentException("I said don't type 'foo'!");
        }
        _thingy = value;
      }
    }
    public MyContext() {
    }
  }
  public partial class MainPage : PhoneApplicationPage {


    // Constructor
    public MainPage() {
      InitializeComponent();
      this.DataContext = new MyContext();
    }

  }
}

我已经搜索了这个线索,但是当ValidateOnExceptions = true并且WP8支持时,它应该提供视觉反馈,这似乎很明确:

http://msdn.microsoft.com/en-us/library/windowsphone/develop/cc278072(v=vs.105).aspx#BKMK_Datavalidation

1 个答案:

答案 0 :(得分:0)

我们的程序Terminator使用IErrorInfo和朋友验证地理坐标。

您可能会发现验证机制正常,但您需要在控件模板中向Visual State Manager添加正确的样式。这是我们的验证文本框stye

  <Style x:Key="ValidatingTextBox" TargetType="TextBox">
    <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilyNormal}"/>
    <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
    <Setter Property="Background" Value="{StaticResource PhoneTextBoxBrush}"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneTextBoxForegroundBrush}"/>
    <Setter Property="BorderBrush" Value="{StaticResource PhoneTextBoxBrush}"/>
    <Setter Property="SelectionBackground" Value="{StaticResource PhoneAccentBrush}"/>
    <Setter Property="SelectionForeground" Value="{StaticResource PhoneTextBoxSelectionForegroundBrush}"/>
    <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
    <Setter Property="Padding" Value="2"/>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="TextBox">
          <Grid Background="Transparent">
            <VisualStateManager.VisualStateGroups>
              <VisualStateGroup x:Name="ValidationStates">
                <VisualState x:Name="Valid" >
                  <Storyboard Duration="00:00:01">
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
                                       Storyboard.TargetName="WarningEllipse">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
                                       Storyboard.TargetName="WarningText">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="InvalidUnfocused">
                  <Storyboard Duration="00:00:01">
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
                                       Storyboard.TargetName="WarningEllipse">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Visible</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                    <!-- note the warning text is not shown if unfocused -->
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
                                       Storyboard.TargetName="WarningText">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="InvalidFocused">
                  <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
                                       Storyboard.TargetName="WarningText">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Visible</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
                                       Storyboard.TargetName="WarningEllipse">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Visible</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                  </Storyboard>
                </VisualState>
              </VisualStateGroup>
              <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="MouseOver"/>
                <VisualState x:Name="Disabled">
                  <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DisabledOrReadonlyBorder">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Visible</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="ReadOnly">
                  <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DisabledOrReadonlyBorder">
                      <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                          <Visibility>Visible</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="DisabledOrReadonlyBorder">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="DisabledOrReadonlyBorder">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="DisabledOrReadonlyContent">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxReadOnlyBrush}"/>
                    </ObjectAnimationUsingKeyFrames>
                  </Storyboard>
                </VisualState>
              </VisualStateGroup>
              <VisualStateGroup x:Name="FocusStates">
                <VisualState x:Name="Focused">
                  <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="EnabledBorder">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBackgroundBrush}"/>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="EnabledBorder">
                      <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBorderBrush}"/>
                    </ObjectAnimationUsingKeyFrames>
                  </Storyboard>
                </VisualState>
                <VisualState x:Name="Unfocused"/>
              </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <Border x:Name="EnabledBorder"
                  BorderBrush="{TemplateBinding BorderBrush}"
                  BorderThickness="{TemplateBinding BorderThickness}"
                  Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">
              <Grid>
                <Grid.RowDefinitions>
                  <RowDefinition Height="Auto" />
                  <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <ContentControl Grid.Row="0" x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch"
                        Margin="{StaticResource PhoneTextBoxInnerMargin}"
                        Padding="{TemplateBinding Padding}"
                        VerticalContentAlignment="Top"/>
                <Ellipse Grid.Row="0"
                    x:Name="WarningEllipse"  Visibility="Collapsed"
                    Margin="12,12,12,0"
                    VerticalAlignment="Top"
                    HorizontalAlignment="Right"
                    Width="14" Height="14"
                    Stroke="#40000000" StrokeThickness="2" Fill="Red">
                </Ellipse>
                <TextBlock x:Name="WarningText" Grid.Row="1" Foreground="Red"  Visibility="Collapsed" TextWrapping="Wrap"
                        Margin="3,-12,3,0"
                         Text="{Binding RelativeSource={RelativeSource TemplatedParent}, 
                              Path=(Validation.Errors)[0].ErrorContent, FallbackValue=''}"></TextBlock>
              </Grid>
            </Border>
            <Border x:Name="DisabledOrReadonlyBorder" BorderBrush="{StaticResource PhoneDisabledBrush}"
                  BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent"
                  Margin="{StaticResource PhoneTouchTargetOverhang}" Visibility="Collapsed">
              <TextBox x:Name="DisabledOrReadonlyContent"
                     Background="Transparent"
                     Foreground="{StaticResource PhoneDisabledBrush}"
                     FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}"
                     FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}"
                     IsReadOnly="True" SelectionForeground="{TemplateBinding SelectionForeground}"
                     SelectionBackground="{TemplateBinding SelectionBackground}" TextAlignment="{TemplateBinding TextAlignment}"
                     TextWrapping="{TemplateBinding TextWrapping}" Text="{TemplateBinding Text}"
                     Template="{StaticResource PhoneDisabledTextBoxTemplate}"/>
            </Border>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>