0

I have a working prototype for a rotating Compass UX element in a WPF app. I have the code behind and math worked out to capture the mouse, and rotate the compass with the mouse down so that North always follows the mouse position. This is a standalone UserControl object that I declare in the main Xaml page where I plug into various events I need. This post is how I did the code behind, and this is how I bound the Angle property so I could have the app logic set the value without any direct input on the control.

Recently, I've started porting my prototype into the production repo which is organized into an MVVM pattern. I have the simple click events wired up to the right commands, but the UX does not rotate now that it is in the new, production project. Doing a console print shows that my mouse is being captured, and the codebehind is reaching the exact, expected angle I want applied to the UX, but it does not change.

I have tried a couple alternative approaches, but nothing is getting my original behavior again. Initially, I tried declaring the dependancy property in my ViewModel, with no change. I have also tried creating the RotateTransform and directly setting the control's RenderTransform, but this creates a very erratic behavior (but it does start rotating!)

Connecting to the MainViewModel and setting TwoWay binding is new to my MVVM project, with the commented out line being how I have the working binding in my prototype.

    <Image x:Name="Compass" RenderTransformOrigin="0.5,0.5" >
        <Image.DataContext>
            <p:MainViewModel/>
        </Image.DataContext>
        <Image.RenderTransform>
            <RotateTransform Angle="{Binding BearingAngle, Mode=TwoWay}"/>
            <!--RotateTransform Angle="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type p:CompassView}}, Path=Angle}"/-->
        </Image.RenderTransform>
    </Image>

The code behind that works has the following DependencyProperty.

        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle", typeof(double), typeof(CompassControl), new UIPropertyMetadata(0.0));

        public double Angle
        {
            get { return (double)GetValue(AngleProperty); }
            set { SetValue(AngleProperty, value); }
        }

The closest I have to getting any movement in the MVVM project sets the transform as follows (NOTE, this causes my rotation to flicker 90-180 degrees out of phase with a seemingly random angle, does not have any pattern to following the cursor):

this.RenderTransform = new RotateTransform(this.Angle, knobCenter.X, knobCenter.Y);

Ultimately, the production repo being organized as MVVM might be a red herring and I'm overlooking something else, but since I am relatively inexperienced with how MVVM is supposed to work, that's my only indication of why it's not working in this project but is fine in a prototype demo.

UPDATE: Turns out my problem was unrelated to all of this. A parent control that created my Compass was overwriting the Image property (along with it's RenderTransform) with a custom Image type, causing the RenderTransform I was trying to manipulate be the incorrect one. I declared my Compass to be of this custom type, and removed the overwriting code in the parent control, and everything was working again as expected. Since this parent control did all the binding for my custom Commands without any direct reference to the DataContext or ViewModel, having the simple binding was enough for everything to see each other from where I needed them. I believe I was getting weird behavior from trying to force some bindings the way I had to in a "simple" app vs fully leveraging the way the ViewModel naturally propagates down throw the controls.

Joshua S.
  • 1
  • 1
  • When using a `DependencyProperty` with `Binding` the .NET property is not being invoked. What you might be experiencing here is that the event is not being raised for you. FYI when it comes to User Controls code behind is fine, as it should not require a View Model. Think of it like a button, you don't need anything to make it appear on the screen apart from XAML. – XAMlMAX Apr 23 '19 at 08:32

1 Answers1

0

The problem is most likely due to setting the DataContext on the Image. The way you are doing it there, will create a new instance of the MainViewModel class, which probably isn't what you want. Typically, the DataContext is set at the Window or UserControl level, and allowed to "flow" through the controls.

You most likely need to bind the DataContext to a property, rather than create a new one.

If you were to post more of your control, and its primary viewmodel, we could help you further.


If I had to guess right now, from your current code, the correct binding might look something like:

<Image x:Name="Compass" 
       RenderTransformOrigin="0.5,0.5" 
       DataContext={Binding Path=SomeCompassViewModelPropertyOnYourMainViewModel" >
Bradley Uffner
  • 16,641
  • 3
  • 39
  • 76
  • While this didn't answer my question, it helped me find my problem. Mentioning the DataContext "flowing" through the controls helped me to better look at the whole project, which led me to realize a parent control was overwriting my properties. I'll update my post to explain what was my problem, but thanks for being an interactive rubber duck for me. :) – Joshua S. Apr 23 '19 at 14:01