Cannot nind Visibility property of a Gauge Range

5 posts, 0 answers
  1. Ludovic Gerbault
    Ludovic Gerbault avatar
    226 posts
    Member since:
    Apr 2009

    Posted 13 Oct 2014 Link to this post

    Hello,

    So here's my problem.
    I'm building an extended control based of a SemiCircleGauge. That gauge includes 3 ranges that are always visible, but with min and max value set at runtime.
    There is also a fourth range that may or may not be visible, property also set at runtime.
    I can bind every other value the way I want to, but not the visibility property. For some reason, it always shows regardless of the value I sent it.

    Here's all related code :

    XAML of the custom control

    <telerik:SemicircleNorthScale x:Name="RudderGaugeScale"
        SweepAngle="140"
        StartAngle="200"
        ShowFirstLabel="False"
        ShowLastLabel="False"
        LabelRotationMode="None"
        MiddleTicks="1"
        MajorTickStep="5"
        EndWidth="0.2"
        StartWidth="0.2"
        FontSize="9.333"
        FontWeight="Bold"
        Foreground="White"
        LabelLocation="OverOutside"
        MajorTickLocation="CenterInside"
        MiddleTickStroke="#00000000"
        MinorTickBackground="#00000000"
        MajorTickStroke="White"
        MiddleTickBackground="#00000000"
        MajorTickBackground="White"
        MajorTickUseRangeColor="True"
        MinorTickStroke="#01FFFFFF"
        MajorTickStrokeThickness="1" >
        <telerik:SemicircleNorthScale.Resources>
            <helpers:BindingProxy x:Key="proxy" Data="{Binding ElementName=RudderGauge}" />
        </telerik:SemicircleNorthScale.Resources>
        <telerik:SemicircleNorthScale.Min>           
            <MultiBinding Converter="{StaticResource AngleScaleDisplayConverter}">
                <Binding ElementName="RudderGauge" Path="MinValue" />
                <Binding ElementName="RudderGauge" Path="DeadAngle" />
            </MultiBinding>
        </telerik:SemicircleNorthScale.Min>
        <telerik:SemicircleNorthScale.Max>
            <MultiBinding Converter="{StaticResource AngleScaleDisplayConverter}">
                <Binding ElementName="RudderGauge" Path="MaxValue" />
                <Binding ElementName="RudderGauge" Path="DeadAngle" />
            </MultiBinding>
        </telerik:SemicircleNorthScale.Max>
        <telerik:SemicircleNorthScale.Ranges>
            <telerik:GaugeRange x:Name="DangerZone1" Background="{Binding Path=ColorDanger, ElementName=RudderGauge, Converter={StaticResource ColorConverter}}" Min="{Binding ElementName=RudderGaugeScale, Path=Min}" Max="{Binding ElementName=RudderGauge, Path=DangerMin}" StartWidth="0.8" />
            <telerik:GaugeRange x:Name="DefaultRange" Min="{Binding ElementName=RudderGauge, Path=DangerMin}" Max="{Binding ElementName=RudderGauge, Path=DangerMax}" Background="{Binding ColorDisplay, ElementName=RudderGauge, Converter={StaticResource ColorConverter}}"  StartWidth="0.8" />
            <telerik:GaugeRange x:Name="Sector2" Min="{Binding ElementName=RudderGauge, Path=Sector2Value}" Max="{Binding ElementName=RudderGauge, Path=DangerMax}" Background="{Binding ColorSector2, ElementName=RudderGauge, Converter={StaticResource ColorConverter}}" Visibility="{Binding Path=Data.DisplaySector2, ElementName=RudderGauge, Converter={StaticResource VisibilityConverter} diagnostics:PresentationTraceSources.TraceLevel=High}" StartWidth="0.8" />
            <telerik:GaugeRange x:Name="DangerZone2" Min="{Binding ElementName=RudderGauge, Path=DangerMax}" Max="{Binding ElementName=RudderGaugeScale, Path=Max}" Background="{Binding ColorDanger, ElementName=RudderGauge, Converter={StaticResource ColorConverter}}" StartWidth="0.8" />
        </telerik:SemicircleNorthScale.Ranges>
        <telerik:SemicircleNorthScale.Indicators>
            <telerik:Needle Value="{Binding ElementName=RudderGauge, Path=CurrentValue}"  />
            <telerik:Marker Value="{Binding ElementName=RudderGauge, Path=SetPoint}" Visibility="{Binding ElementName=RudderGauge, Path=DisplaySetPoint, Converter={StaticResource VisibilityConverter}}"  />
        </telerik:SemicircleNorthScale.Indicators>
    </telerik:SemicircleNorthScale>

    Code behind of the dependency property
    public static DependencyProperty DisplaySector2Property = DependencyProperty.Register("DisplaySector2",
        typeof(bool),
        typeof(ECARudderGauge),
        new PropertyMetadata(DisplaySector2PropertyChanged));
     
    public bool DisplaySector2
    {
        get { return (bool)GetValue(DisplaySector2Property); }
        set { SetValue(DisplaySector2Property, value); }
    }
     
    private static void DisplaySector2PropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        ((ECARudderGauge)o).OnDisplaySector2PropertyChanged((bool)e.NewValue);
    }
     
    private void OnDisplaySector2PropertyChanged(bool newValue)
    {
        DisplaySector2 = newValue;
    }

    Converter

    using System;
    using System.Windows;
    using System.Windows.Data;
    using System.Globalization;
     
    namespace ECAControls.Converters
    {
        public class VisibilityConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                bool param = (bool)value;
                if (param)
                    return Visibility.Visible;
                else
                    return Visibility.Collapsed;
            }
     
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                Visibility state = (Visibility)value;
                if (state == Visibility.Visible)
                    return true;
                else
                    return false;
            }
        }
    }

    Call of the custom control

    <eca:ECARudderGauge x:Name="test1" Grid.Row="0" Grid.Column="1"
                               MinValue="{Binding Path=Rudder.MinValue}"
                               MaxValue="{Binding Path=Rudder.MaxValue}"
                               Steps="{Binding Path=Rudder.Steps, Mode=TwoWay}"
                               CurrentValue="{Binding Path=Rudder.CurrentValue, Mode=TwoWay}"
                               SetPoint="{Binding Path=Rudder.SetPoint, Mode=TwoWay}"
                               DisplaySetPoint="{Binding Path=Rudder.DisplaySetPoint, Mode=TwoWay}"
                               ValidateMeasure="{Binding Path=Rudder.ValidateMeasure, Mode=TwoWay}"
                               StopValue="{Binding Path=Rudder.StopValue, Mode=TwoWay}"
                               Sector2Value="{Binding Path=Rudder.Sector2Value, Mode=TwoWay}"
                               DangerMin="{Binding Path=Rudder.DangerMin, Mode=TwoWay}"
                               DangerMax="{Binding Path=Rudder.DangerMax, Mode=TwoWay}"
                               DeadAngle="{Binding Path=Rudder.DeadAngle, Mode=TwoWay}"
                               DisplaySector2="{Binding Path=Rudder.DisplaySector2, Mode=TwoWay}"
                               Text1="{Binding Path=Rudder.Text1, Mode=TwoWay}"
                               Text2="{Binding Path=Rudder.Text2, Mode=TwoWay}"
                               ColorDisplay="{Binding Path=Rudder.ColorDisplay, Mode=TwoWay}"
                               ColorValue="{Binding Path=Rudder.ColorValue, Mode=TwoWay}"
                               ColorScale="{Binding Path=Rudder.ColorScale, Mode=TwoWay}"
                               ColorSetPoint="{Binding Path=Rudder.ColorSetPoint, Mode=TwoWay}"
                               ColorStop="{Binding Path=Rudder.ColorStop, Mode=TwoWay}"
                               ColorSector2="{Binding Path=Rudder.ColorSector2, Mode=TwoWay}"
                               ColorDanger="{Binding Path=Rudder.ColorDanger, Mode=TwoWay}"
                               ColorNeedle1="{Binding Path=Rudder.ColorNeedle1, Mode=TwoWay}"
                               ColorNeedle2="{Binding Path=Rudder.ColorNeedle2, Mode=TwoWay}"
                               ForeColorCurrentVal="{Binding Path=Rudder.ForeColorCurrentVal, Mode=TwoWay}"
                               BackColorCurrentVal="{Binding Path=Rudder.BackColorCurrentVal, Mode=TwoWay}"/>

    Diag trace of the binding

    01.System.Windows.Data Warning: 56 : Created BindingExpression (hash=32089967) for Binding (hash=25935173)
    02.System.Windows.Data Warning: 58 :   Path: 'DisplaySector2'
    03.System.Windows.Data Warning: 60 : BindingExpression (hash=32089967): Default mode resolved to OneWay
    04.System.Windows.Data Warning: 61 : BindingExpression (hash=32089967): Default update trigger resolved to PropertyChanged
    05.System.Windows.Data Warning: 62 : BindingExpression (hash=32089967): Attach to Telerik.Windows.Controls.Gauge.GaugeRange.Visibility (hash=11099805)
    06.System.Windows.Data Warning: 64 : BindingExpression (hash=32089967): Use Framework mentor <null>
    07.System.Windows.Data Warning: 67 : BindingExpression (hash=32089967): Resolving source
    08.System.Windows.Data Warning: 69 : BindingExpression (hash=32089967): Framework mentor not found
    09.System.Windows.Data Warning: 65 : BindingExpression (hash=32089967): Resolve source deferred
    10.System.Windows.Data Warning: 95 : BindingExpression (hash=32089967): Got InheritanceContextChanged event from GaugeRange (hash=11099805)
    11.System.Windows.Data Warning: 67 : BindingExpression (hash=32089967): Resolving source
    12.System.Windows.Data Warning: 70 : BindingExpression (hash=32089967): Found data context element: <null> (OK)
    13.System.Windows.Data Warning: 74 :     Lookup name RudderGauge:  queried SemicircleNorthScale (hash=21772565)
    14.System.Windows.Data Warning: 78 : BindingExpression (hash=32089967): Activate with root item ECARudderGauge (hash=61735358)
    15.System.Windows.Data Warning: 108 : BindingExpression (hash=32089967):   At level 0 - for ECARudderGauge.DisplaySector2 found accessor DependencyProperty(DisplaySector2)
    16.System.Windows.Data Warning: 104 : BindingExpression (hash=32089967): Replace item at level 0 with ECARudderGauge (hash=61735358), using accessor DependencyProperty(DisplaySector2)
    17.System.Windows.Data Warning: 101 : BindingExpression (hash=32089967): GetValue at level 0 from ECARudderGauge (hash=61735358) using DependencyProperty(DisplaySector2): 'False'
    18.System.Windows.Data Warning: 80 : BindingExpression (hash=32089967): TransferValue - got raw value 'False'
    19.System.Windows.Data Warning: 82 : BindingExpression (hash=32089967): TransferValue - user's converter produced 'Collapsed'
    20.System.Windows.Data Warning: 89 : BindingExpression (hash=32089967): TransferValue - using final value 'Collapsed'
    21.System.Windows.Data Warning: 79 : BindingExpression (hash=32089967): Deactivate
    22.System.Windows.Data Warning: 103 : BindingExpression (hash=32089967): Replace item at level 0 with {NullDataItem}
    23.System.Windows.Data Warning: 63 : BindingExpression (hash=32089967): Detach

    Please feel free to point out my mistake, I must be missing something somewhere. And I'd really like to avoid setting the visibility in code behind
    Thank you
  2. Ludovic Gerbault
    Ludovic Gerbault avatar
    226 posts
    Member since:
    Apr 2009

    Posted 13 Oct 2014 in reply to Ludovic Gerbault Link to this post

    Seems my problem might not be my code after all.
    Setting the visibility property to either collapsed or hidden still doesn't hide the range.
  3. UI for WPF is Visual Studio 2017 Ready
  4. Martin
    Admin
    Martin avatar
    1101 posts

    Posted 16 Oct 2014 Link to this post

    Hello Subileau,

    Indeed, this behavior is not caused by your implementation. It appears because the gauge control is handling the range's Visibility property in its code. Setting a property (or binding) in code has a higher priority than binding in xaml.

    In order to hide the ranges you can use several approaches. For example you can bind the Background property instead of the Visibility and change it between the range's original color and a Transparent brush based on the DisplaySector2 bool property.

    Another approach could be to define an attached property and in its OnPropertyChangedCallback handler to change the range's Visibility.

    public class GaugeUtilities
    {
        public static bool GetIsRangeVisible(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsRangeVisibleProperty);
        }
     
        public static void SetIsRangeVisible(DependencyObject obj, bool value)
        {
            obj.SetValue(IsRangeVisibleProperty, value);
        }
     
        public static readonly DependencyProperty IsRangeVisibleProperty =
            DependencyProperty.RegisterAttached("IsRangeVisible", typeof(bool), typeof(GaugeUtilities), new PropertyMetadata(true, OnRangeVisibilityChanged));
     
        private static void OnRangeVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {  
            var range = d as GaugeRange;
            var isVisible = (bool)e.NewValue;
            range.Visibility = isVisible ? Visibility.Visible : Visibility.Collapsed;
        }
    }
    .
    <telerik:GaugeRange x:Name="Sector2" Min="{Binding ElementName=RudderGauge, Path=Sector2Value}" Max="{Binding ElementName=RudderGauge, Path=DangerMax}" Background="{Binding ColorSector2, ElementName=RudderGauge, Converter={StaticResource ColorConverter}}" StartWidth="0.8" local:GaugeUtilities.IsRangeVisible="{Binding ElementName=RudderGauge, Path=Data.DisplaySector2, IsAsync=True}" />
    Note that, the IsAsync property of the binding is set to true. This is because the attached property callback kicks in before the internal setting of the Visibility.

    For your convenience I prepared a project demonstrating those approaches. Please give it a try and let me know if they are suitable for your case.

    Regards,
    Martin
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  5. Ludovic Gerbault
    Ludovic Gerbault avatar
    226 posts
    Member since:
    Apr 2009

    Posted 16 Oct 2014 Link to this post

    I actually had solved it using a multivalueconverter on my background binding and a secondary binding on the stroke property (visual specificity of my application)

    I still think of it as a weird and unexpected behavior, if not an actual bug, to not be able to set the visibility property of a range.
    FYI, I had build a test project with basically one semicirclenorthgauge, one scale from 0 to 100, and one range from 0 to 10 with visibility set at collapsed. It still showed up regardless.
  6. Martin
    Admin
    Martin avatar
    1101 posts

    Posted 20 Oct 2014 Link to this post

    Hi Subileau,

    I am glad to hear that you achieved your requirement.

    As for the Visibility issues I can confirm setting the Visibility of GaugeRange in xaml does not work. I logged this issue in our feedback portal where you can track its status and vote. If you follow the feedback item you will be notified by email as soon as its status changes. I also updated your Telerik points as a small gesture of gratitude for reporting the issue.

    As a side note, if you set the Visibility in code after the range is loaded, the property's value is applied correctly.

    Regards,
    Martin
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
Back to Top
UI for WPF is Visual Studio 2017 Ready