2014-04-22 270 views
1

我有一個愚蠢的問題,我敢肯定很多人遇到。不過,我無法找到滿意的解決方案。wpf綁定事件後關閉窗口

考慮簡單的項目(請參閱下面的代碼)。當我在字段中鍵入文本並且單擊[x]關閉窗口時,窗口的Closing事件之後出現VeryImportantProperty的更改。結果窗口關閉而沒有要求保存更改。

是否有已知的解決方法或更好的編程技術?我發現的唯一建議是通過啓動一個具有較低優先級的子同步線程(無所事事)來延遲關閉處理程序。然而這並沒有太大的作用,因爲綁定和關閉事件處理程序在同一個線程中運行。

C#:

namespace CloseRequestTestProject { 

    public class MyViewModel : INotifyPropertyChanged { 
     public MyViewModel() { _isDirty = false; _veryImportantProperty = "Change me!"; } 
     public event PropertyChangedEventHandler PropertyChanged; 
     protected virtual void OnPropertyChanged(string propertyName) { 
      PropertyChangedEventHandler handler = this.PropertyChanged; 
      if (handler != null) { 
       var e = new PropertyChangedEventArgs(propertyName); 
       handler(this, e); 
      } 
     } 

     private bool _isDirty; 
     private string _veryImportantProperty; 
     public string VeryImportantProperty { 
      get { return _veryImportantProperty; } 
      set { 
       if (value != _veryImportantProperty) { 
        Trace.TraceWarning("Binding event!"); 
        Trace.TraceWarning("ThreadId is " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()); 
        _isDirty = true; 
        _veryImportantProperty = value; 
        OnPropertyChanged("VeryImportantProperty"); 
       } 
      } 
     } 

     public void viewIsClosing(object sender, CancelEventArgs e) { 
      Trace.TraceWarning("View is closing"); 
      Trace.TraceWarning("ThreadId is " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()); 
      if (_isDirty) { 
       switch (MessageBox.Show("VeryImportantProperty has changed. Save changes?", "Question", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning)) { 
        case MessageBoxResult.Yes: ; break; 
        case MessageBoxResult.No: ; break; 
        default: e.Cancel = true; break; 
       } 
      } 
     } 
    } 

    public partial class MainWindow : Window { 
     public MainWindow() { 
      InitializeComponent(); 
      MyViewModel vm = new MyViewModel(); 
      DataContext = vm; 
      Closing += vm.viewIsClosing; 
     } 

    } 
} 

XAML:

<Window x:Class="CloseRequestTestProject.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <WrapPanel> 
      <TextBlock Text="Very Important Property" VerticalAlignment="Top" Margin="10"/> 
      <TextBox Text="{Binding VeryImportantProperty}" VerticalAlignment="Top" Margin="10" MinWidth="200"/> 
     </WrapPanel> 

    </Grid> 
</Window> 

回答

1

添加UpdateSourceTrigger=PropertyChanged的結合可能是一個良好的開端!

  • 這樣你的虛擬機將達到與最新的UI在任何時候都
  • 和你IsDirty屬性將爲trueViewIsClosing被調用
+0

是的,這確實有效。我想知道是否有其他解決方案。現實生活中的形式往往更爲複雜。 – user3088037

+0

它的工作原理和有投票權? +1如果你有一個更復雜的現實生活形式,隨時發佈。這是對所述問題的正確答案。 – Paparazzi

2

確定。線程與此無關。看起來單擊[x]按鈕不會觸發LostFocus,並且文本框LostFocus和綁定發生在窗口實際關閉或至少已經過關閉事件之後。因此,如果您不想使用PropertyChanged UpdateSourceTrigger,則可能需要使用UpdateSource方法強制綁定事件。下面的主窗口的成員函數的伎倆:

private void TriggerLostFocusBinding() { 
     // Gets the element with keyboard focus. 
     UIElement elementWithFocus = Keyboard.FocusedElement as UIElement; 
     if (elementWithFocus!=null && elementWithFocus is FrameworkElement) { 
      FrameworkElement bindingElement = (elementWithFocus as FrameworkElement); 
      //update all binding expressions found for this element 
      foreach (PropertyDescriptor pd in 
       TypeDescriptor.GetProperties(bindingElement, new Attribute[] { 
        new PropertyFilterAttribute(PropertyFilterOptions.SetValues) 
       })) { 
       DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd); 
       if (dpd != null && dpd.DependencyProperty != null) { 
        BindingExpression be = bindingElement.GetBindingExpression(dpd.DependencyProperty); 
        if (be != null) be.UpdateSource(); 
       } 
      } 
     } 
    } 
+0

雖然接受的解決方案是技術上更好的IMO這種解決方案節省了我不得不修改50+綁定分散在一個大而複雜的窗口。 – apc