UpdateSourceTrigger = Явная

Я создаю окно WPF с несколькими текстовыми полями, когда пользователь нажимает кнопку "ОК". Я хочу, чтобы все текстовые поля были оценены как непустые. Я понимаю, что мне нужно использовать TextBoxes с "UpdateSourceTrigger" "Явно", но нужно ли мне называть "UpdateSource()" для каждого из них? например.

<TextBox Height="23" 
     HorizontalAlignment="Left" 
     Margin="206,108,0,0" 
     Text="{Binding Path=Definition, UpdateSourceTrigger=Explicit}"
     Name="tbDefinitionFolder" 
     VerticalAlignment="Top" 
     Width="120" />

<TextBox Height="23" 
     HorizontalAlignment="Left" 
     Margin="206,108,0,0" 
     Text="{Binding Path=Release, UpdateSourceTrigger=Explicit}"
     Name="tbReleaseFolder" 
     VerticalAlignment="Top" 
     Width="120" />

...

BindingExpression be = tbDefinitionFolder.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
BindingExpression be2 = tbReleaseFolder.GetBindingExpression(TextBox.TextProperty);
be2.UpdateSource();

Ответ 1

Альтернативным подходом может быть установка вашего UpdateSourceTrigger в PropertyChanged.

И затем наследуйте свою виртуальную машину от INotifyPropertyChanged и IDataErrorInfo. Вот пример...

public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    private string myVar;
    public string MyProperty
    {
        [DebuggerStepThrough]
        get { return myVar; }
        [DebuggerStepThrough]
        set
        {
            if (value != myVar)
            {
                myVar = value;
                OnPropertyChanged("MyProperty");
            }
        }
    }
    private void OnPropertyChanged(string prop)
    {
        if(PropertyChanged!=null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(pro));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public string Error
    {
        get { return String.Empty; }
    }
    public string this[string columnName]
    {
        get
        {
            if (columnName == "MyProperty")
            {
                if (String.IsNullOrEmpty(MyProperty))
                {
                    return "Should not be blank";
                }
            }
            return null;
        }
    }
}

Предположим, что один из ваших текстовых полей привязан к "MyProperty", как указано выше. Индексатор реализован в IDataErrorInfo и вызывается при изменении MyProperty. В теле индексатора вы можете выполнить проверку, если значение пустое и вернуть строку ошибки. Если строка ошибки не равна нулю, пользователь получает красивого рекламодателя в TextBox как визуальный сигнал. Таким образом, вы можете сделать один шаг, выполнив проверку и доставку опыта пользовательского интерфейса.

Все это бесплатно, если вы используете два интерфейса, как указано выше, и используйте UpdateSourceTrigger = PropertyChanged. Использование UpdateSourceTrigger = Explicit является массовым излишним избытком для обеспечения проверки, которую вы описали.

Xaml для TextBox будет...

 <TextBox DataContext="{StaticResource Vm}" Text="{Binding MyProperty,
                UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, 
                NotifyOnSourceUpdated=True, Mode=TwoWay}" Width="200" Height="25"/>

Ответ 2

Если вы используете Explicit, вам нужно позвонить UpdateSource.

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

Ответ 3

Есть несколько веских причин использовать UpdateSourceTrigger = Explicit вместо других значений. Представьте, что вам нужно проверить, является ли введенное значение уникальным, что будет сделано путем чтения базы данных. Это может занять некоторое время, даже 0,3 секунды неприемлемо. При использовании PropertyChanged эта проверка базы данных будет выполняться каждый раз, когда пользователь нажимает клавишу, что делает пользовательский интерфейс крайне невосприимчивым. То же самое происходит, если UpdateSourceTrigger = LostFocus и пользователь будет быстро переключаться между элементами управления (если вы удерживаете Tab, между элементами управления будет молниеносная цикличность). Поэтому наша цель - проверить все сразу в ключевой момент (обычно до сохранения данных). Этот подход потребует минимального кода, который будет вытеснять данные из представления в viewmodel и принудительно проверять достоверность. Внутри кода отсутствует код проверки или другая логика приложения, поэтому пуристы MVVM могут быть относительно спокойными. Я создал полностью функциональный пример в VB.NET, который использует Caliburn.Micro для MVVM и IoC. Вы можете скачать его здесь: https://drive.google.com/file/d/0BzdqT0dfGkO3OW5hcjdBOWNWR2M

Ответ 4

Было бы проще просто установить его на UpdateSourceTrigger=PropertyChanged, хотя он будет обновлять базовую переменную каждый раз при изменении значения (для каждой введенной буквы)