1

I am looking at a problem where my own created gauge control doesn't deal with bindings correctly during startup/creation. It works fine once user control and viewmodel are instantiated and all bindings are set.

I have the following control (all user code):

    <linearGauge:LinearGaugeControl
        Grid.Row="2"
        Margin="30, 0, 0, 0"
        GaugeLabel="Flow"
        LinearGaugeLength="800"
        LinearGaugeHeight="80"
        LabelFontSize="20"
        NeedleColor="Black"
        Grid.Column="0" Grid.ColumnSpan="2"
        DataContext="{Binding FlowGaugeData}" />

This question is about two properties in the xaml above:

  • LinearGaugeLength="800"
  • LinearGaugeHeight="80"

These properties are bound to the view model of the LinearGaugeControl :

<UserControl.Resources>
    <Style TargetType="local:LinearGaugeControl">
        <Setter Property="LinearGaugeLength" Value="{Binding GaugeSize, Mode=OneWayToSource}"/>
        <Setter Property="LinearGaugeHeight" Value="{Binding BarThickness, Mode=OneWayToSource, NotifyOnSourceUpdated=True}"/>
    </Style>
</UserControl.Resources>

From my previous struggle with DPs I learned something useful from user ASh, that I can add a callback to my DP so that I at least know that it gets triggered. That works fine. The callback of the LinearGaugeHeight DP fires with the 'new' value of 80 (old value=50).

After that event, my setter gets called, with the wrong value ! (50, the default value of the DP).

What is going wrong?

Is this going wrong because the view is created before the viewmodel is?

In reply to @Clemens:

We are using caliburn, can that in some way cause this problem? I think I read somewhere that caliburn uses DataContext=this under the hoods?

bas
  • 13,550
  • 20
  • 69
  • 146
  • 2
    "*These properties are bound to the GaugeViewModel in the user control itself*" - this is the source of all evil. A UserControl should not have its own view model at all. Instead, just handle property value changes in PropertyChangedCallbacks in the control's code behind. – Clemens Dec 18 '19 at 13:54
  • Don't user controls often have view models in a MVVM world? – bas Dec 18 '19 at 14:00
  • No, they should never have their own view model. Unfortunately there are a lot of blogs on the internet where people show UserControls with private view models, but they are wrong. A UserControl (or a control in general) should expose bindable properties that are bound to properties of a (view model) object in its DataContext, which it gets from its parent element by property value inheritance. Value changes of its properties should be handled by PropertyChangedCallbacks in the control's code behind. – Clemens Dec 18 '19 at 14:04
  • Is there any reference that you could point me to? Because then I am using WPF wrong for a long long time. I must admit two things; 1) I am really frustrated at this moment that again I followed a path in WPF which again "seemed to work perfectly almost all the way", but also 2) I am very interested in fully understanding what you mention here, because that just might prevent me from doing 1) ever again.... – bas Dec 18 '19 at 14:08
  • 1
    If you search StackOverflow for e.g. "wpf usercontrol datacontext" you'll find a lot of question where people ask why binding their UserControl's properties doesn't work. Often these controls have something like `DataContext = this;` or `DataContext = new MyPrivateControlViewModel();` in their code behind, which effectively breaks Bindings like `` – Clemens Dec 18 '19 at 14:59
  • I don't think we are talking about the same problem here. I don't have code behind like `DataContext = this` or anything. The datacontext is set to the window, and inherited by the page which uses my control. I don't see much harm in that. – bas Dec 20 '19 at 11:58
  • PS: this control works completely fine in a standalone solution. The only difference I can think of, is that I don't rely on caliburn in my standalone solution, but we **do** rely on caliburn in the context where things go wrong – bas Dec 20 '19 at 12:01

0 Answers0