NotifyPropertyChanged執行緒與介面繫結非同步更新
阿新 • • 發佈:2018-12-12
為了解決NotifyPorpertyChanged的執行緒與介面繫結非同步更新衝突問題,所以檢視相關資料後,將自己的NotifyPropertyChanged作了改進。
1.問題起因
在開發C#應用程式,通常後使用到介面控制元件特定屬性(Enable | Text)與指定的類成員繫結。但如果指定類成員變數線上程中和介面需非同步更新時,會出現異常情況(介面顯示異常)。
以下程式碼未作非同步更新,示例如下:
public class TubeConsumedRecord : INotifyPropertyChanged { /// <summary> /// The lock tube /// </summary> private object lockTube; /// <summary> /// The available count /// </summary> private int availableCount; /// <summary> /// 在屬性值更改時發生。 /// </summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Gets or sets the available tube count. /// </summary> /// <value>The available tube count.</value> public int AvailableTubeCount { get { return availableCount; } set { if (this.availableCount == value) { return; } this.availableCount = value; OnPropertyChanged(new PropertyChangedEventArgs("AvailableTubeCount")); } } /// <summary> /// Handles the <see cref="E:PropertyChanged" /> event. /// </summary> /// <param name="e">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param> private void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) PropertyChanged(this, e); } /// <summary> /// Initializes a new instance of the <see cref="TubeConsumedRecord"/> class. /// </summary> public TubeConsumedRecord() { this.lockTube = new object(); } }
2. 解決方法
為了解決屬性繫結的介面和執行緒非同步更新時衝突問題,對INotifyPropertyChanged作了相應的改造。
改造後的類AsynNotifyPropertyChanged, 直接繼承使用。
設定非同步上下文類為SynchronizationContextProvider,需要使用者設定介面的非同步上下文,在創造主窗體Main()中新增。
SynchronizationContextProvider.CreateSynchronizationContext(WindowsFormsSynchronizationContext.Current);
AsynNotifyPropertyChanged程式碼如下:
public class AsynNotifyPropertyChanged : INotifyPropertyChanged { /// <summary> /// Initializes a new instance of the <see cref="AsyncBindingData"/> class. /// </summary> public AsynNotifyPropertyChanged() { } /// <summary> /// Occurs when a property value changes. /// </summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Called when [property changed]. /// </summary> /// <param name="propertyName">Name of the property.</param> public void OnPropertyChanged(string propertyName) { if (this.PropertyChanged == null||string.IsNullOrEmpty(propertyName)) { return; } if (SynchronizationContextProvider.UISynchronizationContext != null) { SynchronizationContextProvider.UISynchronizationContext.Send(new SendOrPostCallback(AysnPropertyChanged), propertyName); } else { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } private void AysnPropertyChanged(object state) { string propertyName = state.ToString(); if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public void OnPropertyChanged(object sender, PropertyChangedEventHandler propertyChanged, string propertyName) { if (propertyChanged == null || string.IsNullOrEmpty(propertyName)) { return; } if (SynchronizationContextProvider.UISynchronizationContext != null) { SynchronizationContextProvider.UISynchronizationContext.Send(new SendOrPostCallback(AysnPropertyChanged), propertyName); } else { propertyChanged(sender, new PropertyChangedEventArgs(propertyName)); } } }
SynchronizationContextProvider類程式碼如下:
public class SynchronizationContextProvider
{
/// <summary>
/// The current
/// </summary>
private static SynchronizationContext current;
/// <summary>
/// Gets the UI synchronization context.
/// </summary>
/// <value>The UI synchronization context.</value>
internal static SynchronizationContext UISynchronizationContext
{
get
{
if(SynchronizationContext.Current==null)
{
SynchronizationContext.SetSynchronizationContext(current);
}
return current;
}
}
/// <summary>
/// Creates the synchronization context.
/// </summary>
/// <param name="context">The context.</param>
public static void CreateSynchronizationContext(SynchronizationContext context)
{
current = context;
}
}