Search code examples
c#wpfxamlinheritance

WPF How do I reference x:Name elements in code behind of a base view


I have several views that could benefit from a base class. Each derived view has this XAML.

        <oxy:PlotView x:Name="Plot" Model="{Binding PlotModel}" Grid.Column="2" Loaded="Plot_OnLoaded" Unloaded="Plot_UnLoaded" MinHeight="{Binding MinimumPlotHeight}">

I want this code to be in the base class.

    protected void Plot_OnLoaded(object sender, RoutedEventArgs e)
    {
        foreach (var axis in Plot.ActualModel.Axes)
        {
            if (axis.Position != AxisPosition.Bottom)
                continue;
        
            XAxis = axis;
            break;
        }
        
        if (XAxis != null)
            XAxis.AxisChanged += OnAxisChanged;
    }

As you see it references Plot, which the base class has no knowledge of. I tried adding a property to the base class, to let it know what Plot is.

public PlotView Plot { get; set; }

This allows the everything to compile and run, but Plot is just null, which I guess is no surprise. How can I let the base class know about this name in the derived XAML?


Solution

  • I used a variation of Clemens' and BionicCode's suggestions. I defined this property:

    public PlotView Plot { get; private set; }
    

    and modified the onloaded handler.

        protected void Plot_OnLoaded(object sender, RoutedEventArgs e)
        {
            Plot = sender as PlotView;
            foreach (var axis in Plot.ActualModel.Axes)
            {
                if (axis.Position != AxisPosition.Bottom)
                    continue;
            
                XAxis = axis;
                break;
            }
            
            if (XAxis != null)
                XAxis.AxisChanged += OnAxisChanged;
        }
    

    I made Plot a public property because I am also using it in the base class here.

        protected void OnAxisChanged(object sender, AxisChangedEventArgs e)
        {
            // if true then stop any recursion
            if (IsInternalChange)
                return;
    
            var xMin = XAxis.ActualMinimum;
            var xMax = XAxis.ActualMaximum;
    
            foreach (SyncrhonisedTrackView track in _parentView.TrackList)
            {
                if (track == this)
                    continue;
    
                track.IsInternalChange = true;
    
                // do not use zoom to set axis, it can lead to recursion
                track.XAxis.AbsoluteMinimum = xMin;
                track.XAxis.AbsoluteMaximum = xMax;
                track.Plot.InvalidatePlot(false);
                track.IsInternalChange = false;
            }
        }
    

    Hopefully that will satisfy any design issues.