2010-07-19 13 views
5

मेरे पास एक combobox और टेक्स्टबॉक्स के साथ एक WPF फॉर्म है (दोनों ऑब्जेक्ट की संपत्ति के लिए डेटाबेस हैं)। कंबोबॉक्स या टेक्स्टबॉक्स इनपुट को बदलना ऑब्जेक्ट की प्रॉपर्टी अपडेट करता है और डाटाबेसिंग यूआई को अपडेट करता है और अपडेट करता है। समस्या यह है कि, मैंने परिवर्तन को रद्द करने का एक तरीका लागू किया, जो काम करता है, लेकिन यूआई अपडेटिंग को खराब करता है। यदि मैं combobox से परिवर्तन करता हूं और इसे रद्द करता हूं, तो combobox चयनित औसत को वापस उस चीज़ पर वापस नहीं लाता है (ऑब्जेक्ट के मान से बाध्य)। यदि मैं टेक्स्टबॉक्स से परिवर्तन करता हूं और इसे रद्द करता हूं, तो टेक्स्टबॉक्स और कम्बोबॉक्स दोनों उचित डेटा दिखाते हैं, लेकिन फिर फोकस तुरंत कम्बोबॉक्स को दिया जाता है (जब इसे टेक्स्टबॉक्स पर रहना चाहिए क्योंकि यह आखिरी जगह है यह)। मुझे सचमुच यकीन नहीं है कि परिवर्तन घटनाओं को संभालने के लिए लगाए गए सामान्य पहलू में इसे ठीक करने के बारे में कैसे जाना है और परिवर्तन को सत्यापित करना बाद में रद्द नहीं किया गया था (क्योंकि डाटाबेसिंग का बिंदु क्या है?) ...WPF डेटा बाइंडिंग: रद्द संपत्ति परिवर्तन - Combobox misaligns

//User.cs 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Text; 

namespace MyTesting 
{ 
    public class User : AbstractEntity 
    { 
     public User() 
     { 
      Rankings = new Dictionary<int,string>(); 

      Rankings.Add(1, "Newbie"); 
      Rankings.Add(10, "Novice"); 
      Rankings.Add(25, "Adept User"); 
      Rankings.Add(50, "Power User"); 
      Rankings.Add(100, "Admin God"); 
     } 

     public Dictionary<Int32, String> Rankings { get; set; } 

     private Int32 _rank; 
     public Int32 Rank 
     { 
      get 
      { 
       return _rank; 
      } 
      set 
      { 
       SetProperty<Int32>("Rank", ref _rank, value); 
      } 
     } 
    } 
} 


//AbstractEntity.cs 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Text; 

namespace MyTesting 
{ 
    public abstract class AbstractEntity : INotifyPropertyChanging, INotifyPropertyChanged 
    { 
     protected void SetProperty<T>(String propertyName, ref T property, T value) 
     { 
      if (!Object.Equals(property, value)) 
      { 
       if (OnPropertyChanging(propertyName, property, value)) 
       { 
        T oldValue = (T)property; 
        property = value; 
        OnPropertyChanged(propertyName, property, value); 
       } 
      } 
     } 

     [field: NonSerialized] 
     public event PropertyChangingEventHandler PropertyChanging; 

     protected virtual Boolean OnPropertyChanging(String propertyName, Object oldValue = null, Object newValue = null) 
     { 
      CancellablePropertyChangingEventArgs e; 

      if ((oldValue != null) || (newValue != null)) 
       e = new CancellablePropertyChangingEventArgs(propertyName, oldValue, newValue); 
      else 
       e = new CancellablePropertyChangingEventArgs(propertyName); 

      return OnPropertyChanging(e); 
     } 
     protected virtual Boolean OnPropertyChanging(CancellablePropertyChangingEventArgs e) 
     { 
      if (PropertyChanging != null) 
       PropertyChanging(this, e as PropertyChangingEventArgs); 

      return !e.IsCancelled; 
     } 

     [field: NonSerialized] 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected virtual void OnPropertyChanged(String propertyName, Object oldValue = null, Object newValue = null) 
     { 
      ExtendedPropertyChangedEventArgs e; 

      if ((oldValue != null) || (newValue != null)) 
       e = new ExtendedPropertyChangedEventArgs(propertyName, oldValue, newValue); 
      else 
       e = new ExtendedPropertyChangedEventArgs(propertyName); 

      OnPropertyChanged(e); 
     } 
     protected virtual void OnPropertyChanged(ExtendedPropertyChangedEventArgs e) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, e as PropertyChangedEventArgs); 
     } 
    } 

    public class ExtendedPropertyChangedEventArgs : PropertyChangedEventArgs 
    { 
     public ExtendedPropertyChangedEventArgs(String propertyName) 
      : base(propertyName) 
     { 
     } 

     public ExtendedPropertyChangedEventArgs(String propertyName, Object oldValue, Object newValue) 
      : base(propertyName) 
     { 
      OldValue = oldValue; 
      NewValue = newValue; 
     } 

     public Object OldValue { get; private set; } 
     public Object NewValue { get; private set; } 
    } 

    public class CancellablePropertyChangingEventArgs : PropertyChangingEventArgs 
    { 
     public CancellablePropertyChangingEventArgs(String propertyName, Boolean cancel = false) 
      : base(propertyName) 
     { 
      IsCancelled = cancel; 
     } 

     public CancellablePropertyChangingEventArgs(String propertyName, Object oldValue, Object newValue, Boolean cancel = false) 
      : base(propertyName) 
     { 
      OldValue = oldValue; 
      NewValue = newValue; 

      IsCancelled = cancel; 
     } 

     public Object OldValue { get; private set; } 
     public Object NewValue { get; private set; } 

     public Boolean IsCancelled { get; set; } 
    } 
} 


<!-- MainWindow.xaml --> 
<Window x:Class="ObservableDictionaryBinding.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:src="clr-namespace:MyTesting" 
     Title="MainWindow" Height="350" Width="525" Loaded="OnLoaded"> 

    <Grid> 
     <ComboBox x:Name="RankList" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="12,12,12,0" /> 

     <TextBlock Height="23" Width="40" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="13,100,0,0" Text="Rank:" /> 
     <TextBox x:Name="RankBox" Height="23" HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="59,97,12,0" /> 
    </Grid> 
</Window> 

//MainWindow.xaml.cs 
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace MyTesting 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      MyUser = new User(); 

      InitializeComponent(); 

      MyUser.PropertyChanging += new PropertyChangingEventHandler(MyUser_PropertyChanging); 
     } 

     private User MyUser { get; set; } 

     private Binding RankListBinding { get; set; } 
     private Binding RankBinding { get; set; } 
     private Binding RankListRankBinding { get; set; } 

     private void OnLoaded(object sender, EventArgs e) 
     { 
      DataContext = MyUser; 

      RankListBinding = new Binding("Rankings"); 
      RankListBinding.Source = MyUser; 
      RankList.SetBinding(ComboBox.ItemsSourceProperty, RankListBinding); 
      RankList.SelectedValuePath = "Key"; 
      RankList.DisplayMemberPath = "Value"; 

      RankBinding = new Binding("Rank"); 
      RankBinding.Source = MyUser; 
      RankBox.SetBinding(TextBox.TextProperty, RankBinding); 

      RankListRankBinding = new Binding("Rank"); 
      RankListRankBinding.Source = MyUser; 
      RankList.SetBinding(ComboBox.SelectedValueProperty, RankListRankBinding); 
     } 

     private void MyUser_PropertyChanging(Object sender, PropertyChangingEventArgs e) 
     { 
      CancellablePropertyChangingEventArgs ea = e as CancellablePropertyChangingEventArgs; 

      String text = String.Format("Would you like to change the property '{0}' from '{1}' to '{2}'?", 
        e.PropertyName, 
        (ea.OldValue == null) ? "<null>" : ea.OldValue.ToString(), 
        (ea.NewValue == null) ? "<null>" : ea.NewValue.ToString() 
        ); 

      MessageBoxResult result = MessageBox.Show(this, text, "Property Changed", 
       MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes); 

      if (result == MessageBoxResult.No) 
       ea.IsCancelled = true; 
     } 
    } 
} 

अपडेटेड विधि: यह बाध्यकारी को हल करता है, लेकिन जब समस्या उपयोगकर्ता टेक्स्टबॉक्स में कोई मान बदलने का प्रयास करता है तो उस समस्या को हल नहीं करता है जो कि combobox द्वारा फ़ोकस चोरी हो जाता है, फिर उसे रद्द कर देता है। लेकिन, कम से कम यूआई इसके डाटाबेस वैल्यू के मामले में मेल खाता है। मुझे यह link मिला जो मेरी मदद करता था।

protected void SetProperty<T>(String propertyName, ref T property, T value) 
{ 
    if (!Object.Equals(property, value)) 
    { 
     bool cancelled = OnPropertyChanging<T>(propertyName, property, value); 

     if (cancelled) 
     { 
      Application.Current.Dispatcher.BeginInvoke(
       new Action(() => 
       { 
        OnPropertyChanged<T>(propertyName); 
       }), 
       DispatcherPriority.ContextIdle, 
       null 
      ); 

      return; 
     } 

     T originalValue = property; 
     property = value; 
     OnPropertyChanged(propertyName, originalValue, property); 
    } 
} 

उत्तर

1

यह यूआई उचित डेटाबाउंड डेटा प्रदर्शित हल करती है ... यह सिर्फ चोरी फोकस समस्या ठीक नहीं होती:

protected void SetProperty<T>(String propertyName, ref T property, T value) 
{ 
    if (!Object.Equals(property, value)) 
    { 
     bool cancelled = OnPropertyChanging<T>(propertyName, property, value); 

     if (cancelled) 
     { 
      Application.Current.Dispatcher.BeginInvoke(
       new Action(() => 
       { 
        OnPropertyChanged<T>(propertyName); 
       }), 
       DispatcherPriority.ContextIdle, 
       null 
      ); 

      return; 
     } 

     T originalValue = property; 
     property = value; 
     OnPropertyChanged(propertyName, originalValue, property); 
    } 
} 
0

उपयोगकर्ता एक संपत्ति परिवर्तन आप अभी भी पुराने मूल्य के साथ INotifyPropertyChanged.PropertyChanged पोस्ट करना चाहिए रद्द कर दिए जाने। यदि आपके बाइंडिंग दो बार हैं तो उपयोगकर्ता द्वारा बदला गया कोई भी नियंत्रण वापस बदलेगा।

+1

मैं संपत्ति की स्थापना और फिर इसे वापस करने के लिए निर्धारित करके इसे ठीक करने का प्रयास किया है पुराने मूल्य, प्रत्येक बार OnPropertyChanged को कॉल करते हैं, जो 2 अलग-अलग ईवेंट (जैसा कि 2 अलग-अलग कॉल के साथ अपेक्षित है) उठाता है, लेकिन अंत में कम्बोबॉक्स अभी भी रद्द होने पर ठीक से अपडेट नहीं हो रहा है। (ओह, और मैंने जेनिक्स को अन्य विधियों के लिए भी अद्यतन किया, न कि यह कुछ भी प्रभावित करता है)। –

संबंधित मुद्दे