Question

I have encounted a problem when switching to the .NET Framework 4.0. I have a window that uses twoway binding on its Top/Left & Widht/Height properties.

A problem occurs when i need to change the viewModel.

After changing the underlying ViewModel, when triggering the PropertyChanged event on the propertyname corresponding to my viewModel, the Left property's binding is triggered, moving the window to the correct X-location. But the action of moving the window triggers a "to source", setting my viewModel's Top property. EDIT : There is not "set" done, but the Y Binding is not processed.

Same behavior with the Height & Width properties.

Here is a tiny application that shows my problem.

here is the model :

 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;
    }
}

And here is the view :

<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>

And finally the code-behind :

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();
        }
    }
}

What I would've liked to know is if there is some kind a way to "freeze" a binding, to prevent the engine from setting my viewModel until it has finished processing all the binding I asked it to do. or to switch the binding from twoWay to OneWay, for a short period of time.

The small application here behaves correctly when using the .NET framework 3.5 but doesn't with the 4.0.

I am surprised I couldn't find anyone struggling with the same issue, am i doing something wrong ? I thank you for your answers, don't hesitate to ask if something is not clear.

Jean-Loup Kahloun


I've added logs this morning (i should've done that before posting here..), just like you did, and you are right, there is no "set" done, but the Y binding is not processed. The behavior is even more strange when actually toggling several times the position of the window.

I'm going to test your solution, even though I would have liked to avoid using code behind ( I used some for test purposes only ).

I thank you for answering so fast, i'll get back at you when I have some time to find a code-behind-free solution. As the model is not set, i may be able to trigger seperately the X and Y bindings with propertychanged events, right after the weird-behaving "Position" binding is triggered.

Thanks again, i was going the wrong way, you saved me loads of time.

Was it helpful?

Solution

I'm not sure I agree with your point

But the action of moving the window triggers a "to source", setting my viewModel's Top property.

I have run your code and I can confirm that the window moves from (5, 5) to (500, 5) when you click the 'Change Position' button. However, I then added another button whose Click event handler wrote the values of the window's Left and Top values to the debug log. I found that this reported that the window was apparently at (500, 500). I then dragged it a short distance, clicked this button again and was then informed that the window was at (498, 4).

I think the bindings are working correctly, but for some reason, Windows doesn't move the window when its Left and Top properties both change via bindings in quick succession. I'm not sure why this happens; it could be a bug in .NET 4, especially if it worked in .NET 3.5.

I found that the window behaved a bit more as I would expect it to if I added a dependency property of type Position and bound that direct to SelectedPos rather than binding the window's Left and Top properties to the individual X and Y coordinates inside SelectedPos. When this dependency property changed, I set the window's Left and Top values to the X and Y values within the Position.

The dependency property and property-changed callback I added was as follows:

    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;
    }

I found that the binding had to be made in code-behind. I added this line to the MainWindow constructor:

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

Finally, I deleted the bindings on Left and Top in the main window.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top