2009-03-03 11 views
0

J'ai une zone de texte liée à mon objet de données. Si la validation échoue, je voudrais montrer un popup qui contient le message d'erreur. En XAML cela fonctionne bien. J'utilise le XAML suivant:Comment lier à Popup.IsOpen à Validation.HasError dans le code

<TextBox Height="23" Margin="54,12,104,0" Name="textBox1" 
VerticalAlignment="Top" Text="{Binding Value, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"></TextBox> 

     <Popup Name="myPopup" PlacementTarget="{Binding ElementName=textBox1}" 
         IsOpen="{Binding ElementName=textBox1, Path=(Validation.HasError), Mode=OneWay}" 
         > 
      <TextBlock Name="myPopupText" Background="LightBlue" Foreground="Blue"> 
         The value is invalid 
      </TextBlock> 
     </Popup> 

Mon problème est que je dois créer le menu contextuel et obligatoire dans le code et je ne peux pas le faire fonctionner. J'ai essayé plusieurs options différentes. J'ai également utilisé le convertisseur de dummy juste pour voir si la liaison fonctionne du tout. Il semble que la reliure fonctionne quand je la crée (elle obtient la valeur initiale) mais après cela rien ne se passe. Je peux voir que le Validation.HasError se met à jour correctement (la bordure de TextBox devient rouge), mais c'est tout. Mon convertisseur fictif n'est pas appelé. Voici le code que j'utilise:

Popup popup = new Popup(); 
    popup.Name = "somepopup"; 
    // Source is the textbox which is bound to the data object 
    popup.PlacementTarget = source; 
    popup.Placement = PlacementMode.Bottom; 
    TextBlock txtblock = new TextBlock(); 
    txtblock.Background = Brushes.LightBlue; 
    txtblock.Foreground = Brushes.Blue; 
    txtblock.Text = "this is the error message"; 
    popup.Child = txtblock; 

    Binding is_open_binding = new Binding("(Validation.HasError)"); 
    is_open_binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 
    is_open_binding.Source = source; 
    is_open_binding.Mode = BindingMode.OneWay; 
    is_open_binding.NotifyOnValidationError = true; 
    is_open_binding.ValidatesOnExceptions = true; 
    is_open_binding.Converter = new TempValueConverter(); 
    popup.SetBinding(Popup.IsOpenProperty, is_open_binding); 

Répondre

3

Juste fait un test simple et cela a bien fonctionné. Voici mon XAML:

<Window x:Name="_root" x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel> 
     <TextBox x:Name="_textBox"> 
      <TextBox.Text> 
       <Binding Path="Text" ElementName="_root" UpdateSourceTrigger="PropertyChanged"> 
        <Binding.ValidationRules> 
         <ExceptionValidationRule/> 
        </Binding.ValidationRules> 
       </Binding> 
      </TextBox.Text> 
     </TextBox> 
     <!--<Popup x:Name="_popup" IsOpen="{Binding (Validation.HasError), ElementName=_textBox, Mode=OneWay}">--> 
     <Popup x:Name="_popup"> 
      <Border BorderThickness="1" BorderBrush="Black" Background="White"> 
       <TextBlock>Here I am.</TextBlock> 
      </Border> 
     </Popup> 
    </StackPanel> 
</Window> 

Et voici le code-behind:

using System; 
using System.Windows; 
using System.Windows.Controls.Primitives; 
using System.Windows.Data; 

namespace WpfApplication1 
{ 
    public partial class Window1 : Window 
    { 
     public string Text 
     { 
      get { return "Text"; } 
      set { if (value != "Text") throw new InvalidOperationException("Bla"); } 
     } 

     public Window1() 
     { 
      InitializeComponent(); 

      var binding = new Binding("(Validation.HasError)"); 
      binding.Source = _textBox; 
      binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 
      binding.Mode = BindingMode.OneWay; 
      binding.NotifyOnValidationError = true; 
      binding.ValidatesOnExceptions = true; 
      //binding.Converter = new TempValueConverter(); 
      _popup.SetBinding(Popup.IsOpenProperty, binding); 
     } 

     private sealed class TempValueConverter : IValueConverter 
     { 
      #region IValueConverter Members 

      public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
      { 
       throw new NotImplementedException(); 
      } 

      public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
      { 
       throw new NotImplementedException(); 
      } 

      #endregion 
     } 
    } 
} 
0

J'ai aussi fait une solution simple et copié dans votre code et il a couru très bien. Kent avait son Popup déclaré en XAML, mais j'ai utilisé votre code exact pour créer le Popup et définir la liaison, de sorte que la différence ne devrait pas être la cause du problème pour vous.

Je me demande si vous pouvez poster d'où vient votre variable source. Vous ne montrez pas cela et je me demande si c'est ce que vous pensez que c'est.

Une autre chose que vous pourriez essayer est de garder une référence à la fenêtre contextuelle au cas où elle serait collectée. Je crois que cela pourrait être possible, car si je me souviens bien, la liaison utilise un gestionnaire d'événement de semaine pour la notification de changement afin qu'ils ne soient pas un lien durable à l'instance de Popup. Je pense que c'est peu probable, mais pourrait valoir la peine. Le code que j'ai utilisé pour tester ceci est le suivant:

fichier XAML:

<Window x:Class="PopupOpenBindingTest.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" 
    Height="300" 
    Width="300"> 
<Grid> 
    <TextBox Height="23" 
      Margin="54,12,104,0" 
      Name="textBox1" 
      VerticalAlignment="Top" 
      Text="{Binding Text, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}" /> 
</Grid></Window> 

code-behind.

public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     InitializeComponent(); 

     DataContext = new DataObjectTest(); 
     this.Loaded += new RoutedEventHandler(Window1_Loaded); 
    } 

    void Window1_Loaded(object sender, RoutedEventArgs e) 
    { 
     TextBox source = textBox1; 

     Popup popup = new Popup(); 
     popup.Name = "somepopup"; 
     popup.PlacementTarget = source; 
     popup.Placement = PlacementMode.Bottom; 
     TextBlock txtblock = new TextBlock(); 
     txtblock.Background = Brushes.LightBlue; 
     txtblock.Foreground = Brushes.Blue; 
     txtblock.Text = "this is the error message"; 
     popup.Child = txtblock; 
     Binding is_open_binding = new Binding("(Validation.HasError)");// { Path = new PropertyPath(Validation.HasErrorProperty) }; 
     is_open_binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 
     is_open_binding.Source = source; 
     is_open_binding.Mode = BindingMode.OneWay; 
     is_open_binding.NotifyOnValidationError = true; 
     is_open_binding.ValidatesOnExceptions = true; 
     //is_open_binding.Converter = new TempValueConverter(); 
     popup.SetBinding(Popup.IsOpenProperty, is_open_binding); 
    } 

    public class DataObjectTest 
    { 
     private string _text = string.Empty; 

     public string Text 
     { 
      get { return _text; } 
      set 
      { 
       if (value.Length > 5) 
        throw new InvalidOperationException("Blah blah blah"); 

       _text = value; 
      } 
     } 
    } 
Questions connexes