Updating control property breaks OneWay binding?

给你一囗甜甜゛ 提交于 2021-01-29 10:04:56

问题


Consider this very simple example where I have a UserControl like this:

UserControl XAML:

<UserControl x:Class="BindingTest.SomeControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Name="SomeControlElement">
    <Grid>
        <TextBlock Text="{Binding ElementName=SomeControlElement, Path=Counter}" />
    </Grid>
</UserControl>

Code Behind:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace BindingTest
{ 
    public partial class SomeControl : UserControl
    {
        public SomeControl()
        {
            InitializeComponent();

            var timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 5);
            timer.Tick += (s, e) => Counter = Counter + 1;
            timer.Start();
        }

        public int Counter
        {
            get { return (int)GetValue(CounterProperty); }
            set { SetValue(CounterProperty, value); }
        }
        public static readonly DependencyProperty CounterProperty = DependencyProperty.Register(nameof(Counter), typeof(int), typeof(SomeControl), new PropertyMetadata(0));
    }
}

So the Control just shows a TextBlock and every 5 seconds increments the Counter. And then I have a consumer of course:

MainWindow XAML:

<Window x:Class="BindingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BindingTest"
        x:Name="MainWindowName" Width="200" Height="300">
    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel>
            <local:SomeControl Counter="{Binding ElementName=MainWindowName, Path=SomeSource, Mode=OneWay}" />
            <local:SomeControl Counter="{Binding ElementName=MainWindowName, Path=SomeSource, Mode=TwoWay}" />
        </StackPanel>
    </Grid>
</Window>

And lastly the Main Code behind:

using System;
using System.Windows;
using System.ComponentModel;
using System.Windows.Threading;
namespace BindingTest
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
            var timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 1);
            timer.Tick += (s, e) => SomeSource = SomeSource + 1;
            timer.Start();
        }

        private int someSource;
        public int SomeSource
        {
            get => someSource;
            set
            {
                if (someSource != value)
                {
                    someSource = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SomeSource)));
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Right, so the main has a counter in code behind that updates a property every second. The XAML has 2 instances of the UserControl. One that has OneWay binding, and one that has TwoWay binding.

What I see here, is that when the Counter in "SomeControl.cs" updates, the binding for the first UserControl (OneWay) is broken. The one with TwoWay keeps on updating.

Is this by design (and why)? And more importantly, if I have the need for updating properties in my UserControls, how would I do this in my example - in order to support OneWay bindings? Mind that, I'm really not interested in TwoWay binding in this example because it would update "MySource" which is not what I wanted!

Thanks.


回答1:


It's by design. When you assign a so-called local value to a dependency property, a previously assigned OneWay Binding is replaced. A TwoWay Binding remains active and updates its source property.

There is however a workaround. Do not set a local value, but a "current value". Replace

timer.Tick += (s, e) => Counter = Counter + 1;

with

timer.Tick += (s, e) => SetCurrentValue(CounterProperty, Counter + 1);


来源:https://stackoverflow.com/questions/51854137/updating-control-property-breaks-oneway-binding

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!