I have a Textbox which is bound to my data object. If the validation fails I would like to show a popup which contains the error message. In XAML this works fine. I'm using the following XAML:
<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>
My problem is that I have to create the popup and binding in code and I cannot get it to work. I have tried several different options. I also used dummy converter just to see whether the binding works at all. It seems that the binding works when I create it (it gets the initial value) but after that nothing happens. I can see that the Validation.HasError updates correctly (TextBox's border turns red), but that's it. My dummy converter is not called. Here is the code I'm using:
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);
-
Just did a simple test and it worked fine. Here is my 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>
And here is the 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 } } }
HTH, Kent
-
I also made a simple solution and copied in your code and it ran just fine. Kent had his Popup declared in XAML, but I used your exact code for creating the Popup and setting the binding, so that difference shouldn't be the cause of the problem for you.
I am wondering if you could post where your source variable is coming from. You don't show that and I am wondering if it is what you think it is.
Another thing you might posibly try is keeping a reference to the popup around incase it is being garbage collected. I believe this could be possible as if I recall correctly the binding uses a week event handler for change notification so their wouldn't be any lasting link to the Popup instance. I think this is unlikely however, but might be worth a shot.
FYI the code I used to test this is as follows.
XAML file:
<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; } } }
0 comments:
Post a Comment