在WPF中编辑对话框,包含绑定和确定/取消按钮

9

如何使用绑定创建一个编辑类属性的对话框,并在对话框中添加确定和取消按钮?

我的第一个想法是这样的:

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

当在switch中,case "OK"时,DataContext包含正确的信息,但最初传递的NewsServer实例不会改变。


如果您展示一下绑定设置,可能会有所帮助。 - Samuel DR
绑定示例:{Binding NeedAuthentication,UpdateSourceTrigger=LostFocus,Mode=TwoWay}。绑定是正确的,因为此.DataContext包含正确的数据。 - ErikTJ
3个回答

8

这是一个老问题,但最近我遇到了这个问题,并发现使用.NET 4.5可以更好地处理它。

首先,将绑定的UpdateSourceTrigger标记为Explicit:

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

然后,在您的“确定”按钮单击事件处理程序中使用以下内容:

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

GetSourceUpdatingBindings是.NET 4.5中的新方法。

取消按钮不需要执行任何操作,因为绑定已被标记为显式,只有在调用UpdateSource时才会“提交”。


5

虽然这是一个老问题,但我会为未来的读者解答...

你需要在绑定中设置UpdateSourceTrigger="Explicit",这样才不会在用户点击确定之前更新实际源。然后在确定按钮处理程序中,你可以编写以下代码:

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

如果您想将绑定重置为初始状态,请使用以下方法。
BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty);  
if (be!=null) be.UpdateTarget(); 

如果您的对话框比较复杂,您可能希望递归遍历其所有控件。


1

原始的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对象本身,有两个选项,可能存在其他选项,第一个可能是最简单的。

  • 在您的NewsServer对象上实现一个void Update(NewsServer source)方法,然后不要对_newsServer字段执行新的赋值,而是调用它的更新方法,并传入DataContext引用值。
  • 使用公共/内部属性公开_newsServer值。您可以通过各种机制使用它:显式响应当属性值更改时引发的事件;绑定到属性(例如使其成为依赖属性或实现INotifyPropertyChanged);或者只需期望调用者在ShowDialog()方法返回true值时检索该值。
请注意,如果您将一些逻辑推回给调用者,您的对话框类可以更简单。特别是,一种方法是仅通过属性向调用者公开克隆对象(例如,完全摆脱_newsServer字段并只使用DataContext)。该对象将像以前一样绑定到对话框的元素上。如果ShowDialog()方法返回true,则调用者将简单地检索此实例的引用。
例如:
NewsServer newsServer = ...;
EditServerDialog editServerDialog = new EditServerDialog(newsServer);

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

如果对话框被取消,调用者将忽略克隆的对象,因此ShowDialog()方法返回false。您可以像上面所示一样重用DataContext属性,或者创建一个不同的属性(例如命名为NewsServer),该属性仅返回DataContext属性值(即使代码更清晰地显示对话框类的公共接口)。

我应该如何做到这一点,同时仍然能够取消和/或应用? - ErikTJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接