How to implements desing time adorner for WPF?

Олег Чижов 0 Reputation points
2024-12-31T16:35:22.22+00:00

I want to provide design-time support for my user control in WPF. I found out about adorners, but unfortunately, I could not implement them (In design time). I used this walkthrough, but it is old and no longer being updated. I would appreciate any help with the topic.

I am sure that I followed that walkthrough correctly.

Metadata.cs:

using Microsoft.Windows.Design.Features;
using System.Activities.Presentation.Metadata;
namespace CustomControlLibrary.VisualStudio.Design
{
    // Container for any general design-time metadata to initialize. 
    // Designers look for a type in the design-time assembly that  
    // implements IRegisterMetadata. If found, designers instantiate  
    // this class and call its Register() method automatically. 
    internal class Metadata : IRegisterMetadata
    {
        // Called by the designer to register any design-time metadata. 
        public void Register()
        {
            AttributeTableBuilder builder = new AttributeTableBuilder();
            // Add the adorner provider to the design-time metadata.
            builder.AddCustomAttributes(typeof(ButtonWithDesignTime), new 	   FeatureAttribute(typeof(OpacitySliderAdornerProvider)));
            MetadataStore.AddAttributeTable(builder.CreateTable());
        }
    }
}

OpacitySliderAdornerProvider.cs:
When I tried to copy-paste code from the walkthrough I noticed that PrimarySelectionAdornerProvider encountered some changes, so I had to change the code.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Microsoft.Windows.Design.Interaction;
using Microsoft.Windows.Design.Model;

namespace CustomControlLibrary.VisualStudio.Design
{
    class OpacitySliderAdornerProvider : PrimarySelectionAdornerProvider
    {
        private ModelItem adornedControlModel;
        private ModelEditingScope batchedChange;
        private Slider opacitySlider;
        private AdornerPanel opacitySliderAdornerPanel;

        public OpacitySliderAdornerProvider()
        {
            opacitySlider = new Slider();
        }
		
		// Activate method now takes only 1 argument
        protected override void Activate(ModelItem item)
        {
            adornedControlModel = item;
            adornedControlModel.PropertyChanged +=
                new System.ComponentModel.PropertyChangedEventHandler(
                    AdornedControlModel_PropertyChanged);

            opacitySlider.Minimum = 0;

            AdornerPanel myPanel = this.Panel;

            AdornerPanel.SetHorizontalStretch(opacitySlider, AdornerStretch.Stretch);
            AdornerPanel.SetVerticalStretch(opacitySlider, AdornerStretch.None);

            AdornerPlacementCollection placement = new AdornerPlacementCollection();

            placement.SizeRelativeToContentWidth(1.0, 0);

            placement.SizeRelativeToAdornerDesiredHeight(1.0, 0);

            placement.PositionRelativeToAdornerHeight(-1.0, 0);

            placement.PositionRelativeToAdornerHeight(0, -5);

            AdornerPanel.SetPlacements(opacitySlider, placement);

            opacitySlider.Loaded += new RoutedEventHandler(slider_Loaded);

            opacitySlider.ValueChanged +=
                new RoutedPropertyChangedEventHandler<double>(
                    slider_ValueChanged);

            opacitySlider.PreviewMouseLeftButtonUp +=
                new System.Windows.Input.MouseButtonEventHandler(
                    slider_MouseLeftButtonUp);

            opacitySlider.PreviewMouseLeftButtonDown +=
                new System.Windows.Input.MouseButtonEventHandler(
                    slider_MouseLeftButtonDown);

			// This line has been changed
            base.Activate(item);
        }

        public AdornerPanel Panel
        {
            get
            {
                if (this.opacitySliderAdornerPanel == null)
                {
                    opacitySliderAdornerPanel = new AdornerPanel();

                    opacitySliderAdornerPanel.Children.Add(opacitySlider);

                    Adorners.Add(opacitySliderAdornerPanel);
                }

                return this.opacitySliderAdornerPanel;
            }
        }


        
        protected override void Deactivate()
        {
            adornedControlModel.PropertyChanged -=
                new System.ComponentModel.PropertyChangedEventHandler(
                    AdornedControlModel_PropertyChanged);
            base.Deactivate();
        }

        void AdornedControlModel_PropertyChanged(
            object sender,
            System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Background")
            {
                opacitySlider.Value = GetCurrentOpacity();
            }
        }

        void slider_Loaded(object sender, RoutedEventArgs e)
        {
            opacitySlider.Value = GetCurrentOpacity();
        }

        void slider_MouseLeftButtonDown(
            object sender,
            System.Windows.Input.MouseButtonEventArgs e)
        {
            batchedChange = adornedControlModel.BeginEdit();
        }

        void slider_MouseLeftButtonUp(
            object sender,
            System.Windows.Input.MouseButtonEventArgs e)
        {
            if (batchedChange != null)
            {
                batchedChange.Complete();
                batchedChange.Dispose();
                batchedChange = null;
            }
        }

        void slider_ValueChanged(
            object sender,
            RoutedPropertyChangedEventArgs<double> e)
        {
            double newOpacityValue = e.NewValue;

            if (newOpacityValue == GetCurrentOpacity())
            {
                return;
            }
			
			// This line has been changed
            ModelProperty backgroundProperty =
                adornedControlModel.Properties["Background"];
            if (!backgroundProperty.IsSet)
            {
                backgroundProperty.SetValue(backgroundProperty.ComputedValue);
            }

            // This line has been changed
            backgroundProperty.Value.Properties["Opacity"].SetValue(newOpacityValue);
        }

        private double GetCurrentOpacity()
        {
			// This line has been changed
            Brush backgroundBrushComputedValue =
                (Brush)adornedControlModel.Properties["Background"].ComputedValue;

            return backgroundBrushComputedValue.Opacity;
        }
    }
}


Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,806 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Jack J Jun 24,626 Reputation points Microsoft Vendor
    2025-01-01T04:52:58.22+00:00

    @Чижов Олег, Welcome to Microsoft Q&A, based on my test, I also could not follow the doc to implements design time adorner for WPF.

    I find the problem comes from the following steps:

    Add references to the following WPF Designer assemblies.

    • Microsoft.Windows.Design
    • Microsoft.Windows.Design.Extensibility
    • Microsoft.Windows.Design.Interaction

    I could not find the assembly about Microsoft.Windows.Design anywhere. However, I see that you want to use System.Activities.Presentation.Metadata to replace it. I also use it to make a test, and it could compile without any errors, but it cannot achieve the function to create a design-time adorner for wpf app.

    It should be correct for your changes in OpacitySliderAdornerProvider.cs.

    Finally, I recommend that you could submit an issue to look for help to find the related dll in the related GitHub .


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.