0

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. Following 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);
4

2 回答 2

3

只是做了一个简单的测试,它工作正常。这是我的 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>

这是代码隐藏:

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
        }
    }
}
于 2009-03-03T11:21:31.293 回答
0

我还做了一个简单的解决方案并复制到你的代码中,它运行得很好。Kent 在 XAML 中声明了他的 Popup,但我使用了您的确切代码来创建 Popup 和设置绑定,因此差异不应该是您的问题的原因。

我想知道您是否可以发布源变量的来源。你没有表现出来,我想知道这是否是你认为的那样。

您可能会尝试的另一件事是保留对弹出窗口的引用,以防它被垃圾收集。我相信这可能是可能的,就好像我正确地记得绑定使用一周事件处理程序来进行更改通知一样,因此它们不会成为到 Popup 实例的任何持久链接。我认为这不太可能,但可能值得一试。

仅供参考,我用来测试的代码如下。

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>

代码隐藏。

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;
            }
        }
    }
于 2009-03-03T11:40:23.837 回答