0

I'm working on a WPF application that uses a UserControl. The UserControl is called ReportControl; here's the XAML:

<UserControl x:Class="ReportManager.Controls.ReportControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:utils="clr-namespace:ReportManager.Utilities"
             xmlns:vms="clr-namespace:ReportManager.ViewModels"
             d:DataContext={d:DesignInstance Type=vms:ReportViewModel}"
             mc:Ignorable="d" >

    <UserControl.Resources>
        <utils:BoolToVisibilityConverter x:Key="BoolToVisibility" True="Visible" False="Collapsed" />
    </UserControl.Resources>

    <Grid>
        <!-- Various controls -->
    </Grid>
</UserControl>

Here's the code behind file:

using System;
using System.Windows;
// Other program specific using statements that aren't relevant
using ReportManager.ViewModels;

namespace RerportManager.Controls
{
    public partial class ReportControl
    {
        public static readonly DependencyProperty ReportProperty =
            DependencyProperty.Register(
                nameof(Report),
                typeof(ReportViewModel),
                typeof(ReportControl),
                new PropertyMetadata(null, PropertyChangedCallback));

        public ReportViewModel Report
        {
            get => (ReportViewModel)GetValue(ReportProperty);
            set => SetValue(ReportProperty, value);
        }

        // Other methods that aren't relevant

        private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // This is where I need help
        }
    }
}

I want the PropertyChangedCallback method to copy the new value of the ReportProperty into the DataContext property. I found another Stack Overflow article Dependency Property dependent on another and I don't understand how to make it work. The examples in the 2 answers don't make sense to me.

The sample in the case that just uses the PropertyChangedCallback looks like this:

private static void OnTestBoolChanged(DependencyObject d, PropertyChangedCallback e)
{
    ViewModel vm = d as ViewModel;
    vm.TestDouble = value ? 100.0 : 200.0;
}

The first thing I know from my own testing is that the argument d is a reference to the control instance (the object that owns the DependencyProperty), so casting it to a ViewModel isn't going to work.

I understand that the DependencyPropertyChangedEventArgs object has NewValue and OldValue properties, which are the new ReportViewModel assigned to the property and null the first time the property is set. So I can get the new ViewModel instance from there.

But I don't understand how to get a reference to the DataContextProperty DependencyProperty so I can set it to the value in e.NewValue. I've tried using the CoerceValue method on the d parameter but I can't get the DataContextProperty from there.

Can anyone help me make this work?

Edit to add: I added this line in the body of the PropertyChangedCallbackmethod and this doesn't work:

d.CoerceValue(DependencyProperty)
Clemens
  • 123,504
  • 12
  • 155
  • 268
Tony Vitabile
  • 8,298
  • 15
  • 67
  • 123
  • You would simply write `((ReportControl)d).DataContext = e.NewValue;`. However, the property is redundant. You do not need the Report property at all when its sole purpose is to set the DataContext. Set or bind the DataContext directly. – Clemens Feb 07 '23 at 06:44
  • Also be aware that setting the DataContext would re-evaluate all Bindings of the properties of your control. When there is a Binding of the Report property, it would get a bew value and the PropertyChangedCallback would be called again. As a general rule, a control should never set its own DataContext, because that may break all Bindings of its properties. – Clemens Feb 07 '23 at 06:47
  • While the example you are referring to uses the uncommon approach to derive a view model class from DependencyObject, it still shows exactly what to do. Cast the DependencyObject argument to the class that owns the changed property and assign a new value to another property. – Clemens Feb 07 '23 at 06:56
  • @Clemens that's exactly what I want to do. This code is used in a window that has a `TreeView` control. When an item in the control is selected, I have a control to the right that displays the details of the selected item. – Tony Vitabile Feb 08 '23 at 01:03

0 Answers0