Диалог редактирования с привязками и OK / Отмена в WPF - PullRequest
6 голосов
/ 01 апреля 2010

Как я могу иметь диалог для редактирования свойств класса с привязкой и иметь OK-Cancel в диалоговом окне?

Моя первая идея была такой:

public partial class EditServerDialog : Window {
    private NewsServer _newsServer;

    public EditServerDialog(NewsServer newsServer) {
        InitializeComponent();

        this.DataContext = (_newsServer = newsServer).Clone();
    }

    private void ButtonClick(object sender, RoutedEventArgs e)
    {
        switch (((Button)e.OriginalSource).Content.ToString()) {
            case "OK":
                _newsServer = (NewsServer)this.DataContext;
                this.Close();
                break;
            case "Cancel":
                this.Close();
                break;
        }
    }
}

Если в коммутаторе указано «ОК», DataContext содержит правильную информацию, но первоначально переданный экземпляр NewsServer не изменяется.

Ответы [ 3 ]

3 голосов
/ 13 октября 2011

Старый вопрос, но я отвечу на него для будущих читателей ...

Вы должны установить UpdateSourceTrigger="Explicit" в своих привязках, чтобы они не обновляли фактический источник, пока пользователь не нажмет OK. Затем в обработчике кнопки ОК вы можете написать:

BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty);  
if (be!=null) be.UpdateSource(); 

Также, если вы хотите сбросить привязки к исходному состоянию, используйте

BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty);  
if (be!=null) be.UpdateTarget(); 

Если ваш диалог сложный, вы можете рекурсивно обойти все его элементы управления.

2 голосов
/ 13 ноября 2014

Это старый вопрос, но я недавно столкнулся с этим и обнаружил, что есть лучший способ справиться с ним .NET 4.5.

Сначала отметьте ваши привязки UpdateSourceTrigger как явные:

<CheckBox IsChecked="{Binding MyProperty, UpdateSourceTrigger=Explicit}"/>

Затем в вашем обработчике нажатия кнопки «ОК» используйте это:

foreach (var be in BindingOperations.GetSourceUpdatingBindings(this))
{
    be.UpdateSource();
}

GetSourceUpdatingBindings - это новый метод в .NET 4.5.

Кнопка отмены не должна ничего делать, поскольку привязки помечены как явные и будут «зафиксированы» только при вызове UpdateSource.

1 голос
/ 01 апреля 2010

Исходный экземпляр вашего NewsServer объекта не изменился, потому что вы на самом деле его не модифицировали. После вызова вашего конструктора у вас есть следующие три NewsServer ссылки:

newsServer = original instance
_newsServer = original instance
DataContext = clone of original instance

После нажатия кнопки ОК ссылки будут следующими:

newsServer = original instance
_newsServer = clone of original instance (possibly modified)
DataContext = clone of original instance (possibly modified)

Помните, что объекты являются ссылочными типами, при присваивании _newsServer вы обновляете только его ссылку, а не значение самого объекта.

Чтобы разрешить обновление самого объекта NewsServer, на ум приходят две опции, вероятно, существуют и другие, первая, вероятно, самая простая.

  • Реализуйте метод void Update(NewsServer source) в своем объекте NewsServer, затем вместо выполнения нового назначения полю _newsServer вместо этого вызовите метод обновления для него и передайте справочное значение DataContext.
  • Укажите значение _newsServer с помощью открытого / внутреннего свойства. Вы можете использовать это с помощью различных механизмов: явное реагирование на событие, которое возникает при изменении значения свойства; привязать к свойству (например, сделать его свойством зависимости или реализовать INotifyPropertyChanged); или просто ожидайте, что вызывающая сторона получит значение, если и когда метод ShowDialog() вернется со значением true.

Обратите внимание, что если вы немного добавите логику к вызывающей стороне, ваш класс диалога может быть проще. В частности, один из подходов состоит в том, чтобы только поддерживать клонированный объект, выставленный вызывающей стороне через свойство (например, полностью избавиться от поля _newsServer и просто использовать DataContext). Этот объект будет привязан к элементам диалога, как и раньше. Вызывающая сторона просто получит ссылку на этот экземпляр в результате true из метода ShowDialog().

Например:

NewsServer newsServer = ...;
EditServerDialog editServerDialog = new EditServerDialog(newsServer);

if (editServerDialog.ShowDialog() == true)
{
    newsServer = editServerDialog.DataContext;
}

Клонированный объект будет просто игнорироваться вызывающей стороной, если диалог отменяется, и, таким образом, метод ShowDialog() возвращает false. Вы можете просто повторно использовать свойство DataContext, как показано выше, или вы можете создать другое свойство (например, с именем NewsServer), которое просто возвращает значение свойства DataContext (то есть, чтобы сделать код немного более понятным в отношении открытого интерфейса класса диалога).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...