powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / DependecnyProperty, Coerce Value и Binding
1 сообщений из 1, страница 1 из 1
DependecnyProperty, Coerce Value и Binding
    #39070975
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Обнаружил очень странно поведение DP.
В чём суть.
Есть некий контрол в котором есть 2 свойства,
для примера X и X2.
При изменении свойства X вызывается d.CoerceValue(X2Property), после чего вызывается метод удержания свойства на нужном значении X2. То есть по сути, X2 всегда будет зависить от X1, и не важно какое мы значение ему задаем. Вроде всё просто.
Но когда я так сделал, обнаружил интересно поведение.
Если привязать поле X2 к обычному (не DP) свойству, то связывание работать не будет и источник значения не будет обновляется после изменения X2;
При этом связывание с другим DP работает отлично, после "принуждения" значения X2, оно обновится и в свойстве источника.

Вот небольшой пример:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
<Window x:Class="WpfApplication40.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfApplication40="clr-namespace:WpfApplication40"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{StaticResource MainModel}">
    <Window.Resources>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Margin" Value="3"/>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <wpfApplication40:MyControl x:Name="MyControl" Grid.Row="1"
                                    X2="{Binding X, Mode=TwoWay}"
                                    Y2="{Binding Y, Mode=TwoWay}"
                                    Background="Transparent"/>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <StackPanel Background="LightCoral">
                <TextBlock Text="Element Binding"/>
                <TextBlock Text="{Binding X,ElementName=MyControl}"/>
                <TextBlock Text="{Binding Y,ElementName=MyControl}"/>
            </StackPanel>
            <StackPanel Background="LightGreen">
                <TextBlock Text="DataContext Binding"/>
                <TextBlock Text="{Binding X}"/>
                <TextBlock Text="{Binding Y}"/>
            </StackPanel>

        </StackPanel>

    </Grid>
</Window>


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WpfApplication40
{
    public class MyControl : Control
    {
        protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e)
        {
            var position = e.GetPosition(this);
            X = position.X;
            Y = position.Y;
        }

        public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }

        public static readonly DependencyProperty XProperty =
            DependencyProperty.Register("X", typeof(double), typeof(MyControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender, OnXChanged));

        private static void OnXChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(X2Property);
        }

        
        public double X2
        {
            get { return (double)GetValue(X2Property); }
            set { SetValue(X2Property, value); }
        }

        public static readonly DependencyProperty X2Property =
            DependencyProperty.Register("X2", typeof(double), typeof(MyControl), new PropertyMetadata(0.0, null, OnX2Coerce));

        private static object OnX2Coerce(DependencyObject d, object basevalue)
        {
            var newValue = (double)d.GetValue(XProperty);
            return newValue + 1;

        }


        public double Y
        {
            get { return (double)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }

        public static readonly DependencyProperty YProperty =
            DependencyProperty.Register("Y", typeof(double), typeof(MyControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender, OnYChanged));

        private static void OnYChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(Y2Property);
        }


        public double Y2
        {
            get { return (double)GetValue(Y2Property); }
            set { SetValue(Y2Property, value); }
        }

        
        public static readonly DependencyProperty Y2Property =
            DependencyProperty.Register("Y2", typeof(double), typeof(MyControl), new PropertyMetadata(0.0, null, OnY2Coerce));

        private static object OnY2Coerce(DependencyObject d, object basevalue)
        {
            var value = (double)basevalue;
            return value + 1;
        }


        protected override void OnRender(DrawingContext drawingContext)
        {
            drawingContext.DrawRectangle(Background, null, new Rect(new Point(0, 0), RenderSize));
            var pen = new Pen(Brushes.Red, 1);
            drawingContext.DrawEllipse(Brushes.Blue, pen, new Point(X, Y), 10, 10);
            base.OnRender(drawingContext);

        }
    }
}


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using WpfApplication40.Annotations;

namespace WpfApplication40
{
    public class MainModel : INotifyPropertyChanged
    {
        private double _x;
        private double _y;

        public double X
        {
            set
            {
                if (value.Equals(_x)) return;
                _x = value;
                OnPropertyChanged("X");
            }
            get { return _x; }
        }

        public double Y
        {
            set
            {
                if (value.Equals(_y)) return;
                _y = value;
                OnPropertyChanged("Y");
            }
            get { return _y; }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


согласен, что такой подход, не очень хороший. Особенно он плох удобочитаемостью, так как для стороннего разработчика будет совершенно не ясно, почему это свойство меняет свое значение и не принимает другие, при этом не являясь readonly.
Но мне просто интересно, с чем это связано?
...
Рейтинг: 0 / 0
1 сообщений из 1, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / DependecnyProperty, Coerce Value и Binding
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]