Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions src/System.Windows.Forms/src/System/Windows/Forms/Binding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,7 @@ internal void UpdateIsBinding()

private class BindToObject
{
private BindingManagerBase _bindingManager;
private PropertyDescriptor _fieldInfo;
private readonly Binding _owner;
private string _errorText = string.Empty;
Expand All @@ -1095,7 +1096,7 @@ private class BindToObject

private void PropValueChanged(object sender, EventArgs e)
{
_owner.BindingManagerBase?.OnCurrentChanged(EventArgs.Empty);
_bindingManager?.OnCurrentChanged(EventArgs.Empty);
}

private bool IsDataSourceInitialized
Expand Down Expand Up @@ -1157,13 +1158,19 @@ private void DataSource_Initialized(object sender, EventArgs e)

internal void SetBindingManagerBase(BindingManagerBase lManager)
{
if (_bindingManager == lManager)
{
return;
}

// remove notification from the backEnd
if (_owner.BindingManagerBase != null && _fieldInfo != null && _owner.BindingManagerBase.IsBinding && !(_owner.BindingManagerBase is CurrencyManager))
if (_bindingManager != null && _fieldInfo != null && _bindingManager.IsBinding && !(_bindingManager is CurrencyManager))
{
_fieldInfo.RemoveValueChanged(_owner.BindingManagerBase.Current, new EventHandler(PropValueChanged));
_fieldInfo.RemoveValueChanged(_bindingManager.Current, new EventHandler(PropValueChanged));
_fieldInfo = null;
}

_bindingManager = lManager;
CheckBinding();
}

Expand Down Expand Up @@ -1200,7 +1207,7 @@ private string GetErrorText(object value)

internal object GetValue()
{
object obj = _owner.BindingManagerBase.Current;
object obj = _bindingManager.Current;

// Update IDataErrorInfo text: it's ok to get this now because we're going to need
// this as part of the BindingCompleteEventArgs anyway.
Expand All @@ -1222,7 +1229,7 @@ internal Type BindToType
{
// if we are bound to a list w/o any properties, then
// take the type from the BindingManager
Type type = _owner.BindingManagerBase.BindType;
Type type = _bindingManager.BindType;
if (typeof(Array).IsAssignableFrom(type))
{
type = type.GetElementType();
Expand All @@ -1240,7 +1247,7 @@ internal void SetValue(object value)

if (_fieldInfo != null)
{
obj = _owner.BindingManagerBase.Current;
obj = _bindingManager.Current;
if (obj is IEditableObject editableObject)
{
editableObject.BeginEdit();
Expand All @@ -1252,7 +1259,7 @@ internal void SetValue(object value)
}
else
{
if (_owner.BindingManagerBase is CurrencyManager cm)
if (_bindingManager is CurrencyManager cm)
{
cm[cm.Position] = value;
obj = value;
Expand All @@ -1274,24 +1281,24 @@ internal void CheckBinding()
}

// Remove propertyChangedNotification when this binding is deleted
if (_owner.BindingManagerBase != null &&
if (_bindingManager != null &&
_fieldInfo != null &&
_owner.BindingManagerBase.IsBinding &&
!(_owner.BindingManagerBase is CurrencyManager))
_bindingManager.IsBinding &&
!(_bindingManager is CurrencyManager))
{

_fieldInfo.RemoveValueChanged(_owner.BindingManagerBase.Current, new EventHandler(PropValueChanged));
_fieldInfo.RemoveValueChanged(_bindingManager.Current, new EventHandler(PropValueChanged));
}

if (_owner.BindingManagerBase != null &&
if (_bindingManager != null &&
_owner.BindableComponent != null &&
_owner.ComponentCreated &&
IsDataSourceInitialized)
{
string dataField = _owner.BindingMemberInfo.BindingField;

_fieldInfo = _owner.BindingManagerBase.GetItemProperties().Find(dataField, true);
if (_owner.BindingManagerBase.DataSource != null && _fieldInfo == null && dataField.Length > 0)
_fieldInfo = _bindingManager.GetItemProperties().Find(dataField, true);
if (_bindingManager.DataSource != null && _fieldInfo == null && dataField.Length > 0)
{
throw new ArgumentException(string.Format(SR.ListBindingBindField, dataField), "dataMember");
}
Expand All @@ -1302,11 +1309,11 @@ internal void CheckBinding()
// if the binding is of the form (Control, ControlProperty, DataSource, Property1.Property2.Property3)
// then we want to get notification from Current.Property1.Property2 and not from DataSource
// when we get the backEnd notification we push the new value into the Control's property
if (_fieldInfo != null && _owner.BindingManagerBase.IsBinding &&
!(_owner.BindingManagerBase is CurrencyManager))
if (_fieldInfo != null && _bindingManager.IsBinding &&
!(_bindingManager is CurrencyManager))
{

_fieldInfo.AddValueChanged(_owner.BindingManagerBase.Current, new EventHandler(PropValueChanged));
_fieldInfo.AddValueChanged(_bindingManager.Current, new EventHandler(PropValueChanged));
}
}
else
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.ComponentModel;

namespace System.Windows.Forms.IntegrationTests.Mocks
{
public class MainObject : INotifyPropertyChanged
{
private string text;
private PropertyChangedEventHandler _propertyChanged;

public string Text
{
get { return text; }
set
{
if (text != value)
{
text = value;
if (_propertyChanged != null)
{
_propertyChanged(this, new PropertyChangedEventArgs(nameof(Text)));
}
}
}
}

public event PropertyChangedEventHandler PropertyChanged
{
add => _propertyChanged += value;
remove => _propertyChanged -= value;
}

public bool IsPropertyChangedAssigned { get { return _propertyChanged != null; } }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace System.Windows.Forms.IntegrationTests
{
public class WinformsControlsTest
public partial class WinformsControlsTest
{
private const string ProjectName = "WinformsControlsTest";
private readonly string _exePath;
Expand Down Expand Up @@ -315,5 +315,27 @@ public void WinformsControlsTest_RichTextBoxesTest()

Assert.True(process.HasExited);
}

[Fact]
public void DataBindings_remove_should_unsubscribe_INotifyPropertyChanged_PropertyChanged_event()
{
var mainObject = new Mocks.MainObject();
mainObject.Text = "Test text";
Form form = new Form();
TextBox textBox = new TextBox();
Binding binding = new Binding("Text", mainObject, "Text");
textBox.DataBindings.Add(binding);
textBox.Parent = form;
form.Show();

// bindings set
Assert.True( mainObject.IsPropertyChangedAssigned);

// remove bindings
textBox.DataBindings.Clear();

// bindings unset
Assert.False(mainObject.IsPropertyChangedAssigned);
}
}
}