Как привязать к Popup.IsOpen к Validation.HasError в коде - PullRequest
0 голосов
/ 03 марта 2009

У меня есть текстовое поле, которое связано с моим объектом данных. Если проверка не удалась, я хотел бы показать всплывающее окно, которое содержит сообщение об ошибке. В XAML это работает нормально. Я использую следующий 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>

Моя проблема в том, что мне нужно создать всплывающее окно и привязку в коде, и я не могу заставить его работать. Я пробовал несколько разных вариантов. Я также использовал фиктивный конвертер, чтобы посмотреть, работает ли привязка вообще. Кажется, что привязка работает, когда я ее создаю (она получает начальное значение), но после этого ничего не происходит. Я вижу, что Validation.HasError корректно обновляется (граница TextBox становится красной), но это все. Мой фиктивный конвертер не называется. Ниже приведен код, который я использую:

    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);

Ответы [ 2 ]

3 голосов
/ 03 марта 2009

Только что сделал простой тест, и он работал нормально. Вот мой 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
        }
    }
}
0 голосов
/ 03 марта 2009

Я также сделал простое решение и скопировал в ваш код, и он работал нормально. У Кента было объявлено его всплывающее окно в XAML, но я использовал ваш точный код для создания всплывающего окна и установки привязки, поэтому различие не должно быть причиной проблемы для вас.

Мне интересно, не могли бы вы опубликовать, откуда берется исходная переменная. Вы не показываете это, и мне интересно, если это то, что вы думаете.

Еще одна вещь, которую вы, вероятно, можете попробовать, - это сохранить ссылку на всплывающее окно, если оно собирает мусор. Я полагаю, что это возможно, как если бы я правильно помню, что привязка использует недельный обработчик событий для уведомления об изменениях, чтобы они не были постоянной ссылкой на экземпляр 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;
            }
        }
    }
...