Двухстороннее связывание с «связанными» переменными (сверху / слева и высотой / шириной) в .NET 4.0 - PullRequest
2 голосов
/ 17 февраля 2012

Я обнаружил проблему при переходе на .NET Framework 4.0.У меня есть окно, которое использует привязку twoway в его свойствах Top / Left & Widht / Height.

Проблема возникает, когда мне нужно изменить viewModel.

После изменения базового ViewModel при запускесобытие PropertyChanged на имя свойства, соответствующее моему viewModel, привязка свойства Left срабатывает, перемещая окно в правильное X-местоположение.Но действие перемещения окна вызывает «к источнику» , устанавливая свойство Top моего viewModel. EDIT : "set" не выполнен, но привязка Y не обрабатывается.

То же поведение со свойствами Height & Width.

Вот крошечное приложениеэто показывает мою проблему.

вот модель:

 public class Model : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public Position SelectedPos { get; set; }
        public Position Pos1 { get; set; }
        public Position Pos2 { get; set; }

    public Model( int x, int y, int x2, int y2 )
    {
        Pos1 = new Position( x, y );
        Pos2 = new Position( x2, y2 );
        SelectedPos = Pos1;
    }

    public void Toggle()
    {
        SelectedPos = Pos2;

        if( PropertyChanged != null )
        {
            var e = new PropertyChangedEventArgs( "SelectedPos" );
            PropertyChanged( this, e );
        }
    }
}

public class Position
{
    int _x;
    public int X
    {
        get { return _x; }
        set { _x = value; }
    }

    int _y;
    public int Y
    {
        get { return _y; }
        set { _y = value; }
    }

    public Position( int x, int y )
    {
        X = x;
        Y = y;
    }
}

И вот мнение:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" 
        Left="{Binding Mode=TwoWay, Path=SelectedPos.X}"
        Top="{Binding Mode=TwoWay, Path=SelectedPos.Y}">
    <Grid>
        <Button Click="Button_Click">Change Position</Button>
    </Grid>
</Window>

И, наконец, код позади:

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        Model model;

        public MainWindow()
        {
            InitializeComponent();
            model = new Model( 5, 5, 500, 500 );
            DataContext = model;
        }

        private void Button_Click( object sender, RoutedEventArgs e )
        {
            model.Toggle();
        }
    }
}

Мне хотелось бы знать, есть ли какой-нибудь способ «заморозить» привязку, чтобы не дать движку установить мою viewModel, пока она не закончит обработку всей привязки, которую я попросил сделать,или на короткое время переключить привязку с двухстороннего на односторонний.

Небольшое приложение работает корректно при использовании .NET Framework 3.5, но не с 4.0.

Я удивлен, что не смог найти никого, кто борется с той же проблемой, я делаю что-то не так?Я благодарю вас за ваши ответы, не стесняйтесь спрашивать, если что-то не ясно.

Жан-Лу Калун


Я добавил журналы сегодня утром (я должен былсделал это перед публикацией здесь ..), так же, как вы сделали, и вы правы, «set» не сделано, но привязка Y не обрабатывается.Поведение становится еще более странным, когда на самом деле несколько раз переключает положение окна.

Я собираюсь протестировать ваше решение, хотя я бы хотел избежать использования кода позади (я использовал некоторые для целей тестированиятолько).

Я благодарю вас за быстрый ответ, я отвечу вам, когда у меня будет время найти решение без кода.Поскольку модель не установлена, я могу иметь возможность отдельно запускать привязки X и Y с событиями, измененными свойством, сразу после срабатывания привязки «Положение» со странным поведением.

Спасибо еще раз, я ошибсяКстати, вы сэкономили мне кучу времени.

1 Ответ

1 голос
/ 17 февраля 2012

Я не уверен, что согласен с вашей точкой зрения

Но действие перемещения окна вызывает «к источнику», устанавливая свойство Top моего viewModel.

Я запустил ваш код и могу подтвердить, что окно перемещается из (5, 5) в (500, 5), когда вы нажимаете кнопку «Изменить позицию».Однако затем я добавил еще одну кнопку, чей обработчик событий Click записал значения значений Left и Top окна в журнал отладки.Я обнаружил, что это сообщило, что окно было очевидно в (500, 500).Затем я перетащил его на небольшое расстояние, снова нажал на эту кнопку, и мне сообщили, что окно было в (498, 4).

Я думаю, что привязки работают правильно, но по какой-то причине Windows не работаетпереместите окно, когда его свойства Left и Top быстро изменятся через привязки.Я не уверен, почему это происходит;это может быть ошибка в .NET 4, особенно если она работает в .NET 3.5.

Я обнаружил, что окно ведет себя немного больше, чем я ожидал, если бы я добавил свойство зависимости типа Position и привязывает это направление к SelectedPos, а не привязывает свойства Left и Top окна к отдельным координатам X и Y внутри SelectedPos.Когда это свойство зависимости изменилось, я установил значения Left и Top окна в значения X и Y в пределах Position.

Свойство зависимости и обратный вызов, измененный свойством, я добавилбыло следующим образом:

    public Position WindowPosition
    {
        get { return (Position)GetValue(WindowPositionProperty); }
        set { SetValue(WindowPositionProperty, value); }
    }

    public static readonly DependencyProperty WindowPositionProperty =
        DependencyProperty.Register("WindowPosition", typeof(Position), typeof(MainWindow), new PropertyMetadata(WindowPosition_Changed));

    private static void WindowPosition_Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var mainWindow = obj as MainWindow;
        mainWindow.Left = mainWindow.WindowPosition.X;
        mainWindow.Top = mainWindow.WindowPosition.Y;
    }

Я обнаружил, что привязка должна быть сделана в коде позади.Я добавил эту строку в конструктор MainWindow:

        SetBinding(WindowPositionProperty, new Binding("SelectedPos"));

Наконец, я удалил привязки для Left и Top в главном окне.

...