Search code examples
c#wpfuser-controlsdependency-properties

Referencing UserControl without Custom Key?


So I'm working on a C#/WPF Application and I'm relatively new to the language/environment. A couple weeks ago, I asked this question: How can I mimic this behavior in WPF?

I wanted to create a sort of pseudo modal popup that would appear/disappear with a click of a button. Adapting the answer given to me, I created the following two classes:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace RelayC
{
    public partial class PopupBase : UserControl
    {
        public PopupBase()
        {
            this.Opacity = 0.0;
            this.Visibility = Visibility.Hidden;
        }

        private void OpenPopup()
        {
            this.Opacity = 1.0;
            this.Visibility = Visibility.Visible;
        }

        private void ClosePopup()
        {
            this.Opacity = 0.0;
            this.Visibility = Visibility.Hidden;

        }

        public bool IsOpen
        {
            get { return (bool)GetValue(IsOpenProperty); }
            set { SetValue(IsOpenProperty, value); }
        }

        public static readonly DependencyProperty IsOpenProperty =
            DependencyProperty.Register(nameof(IsOpen),
                                        typeof(bool),
                                        typeof(PopupBase),
                                        new PropertyMetadata(false,
                                        new PropertyChangedCallback((s, e) =>
                                        {
                                            if (s is PopupBase popupBase && e.NewValue is bool boolean)
                                            {
                                                if (boolean)
                                                {
                                                    popupBase.OpenPopup();
                                                }
                                                else
                                                {
                                                    popupBase.ClosePopup();
                                                }
                                            }
                                        })));

    }

    public class PopupAttach
    {
        public static PopupBase GetPopup(ButtonBase button)
            => (PopupBase)button.GetValue(PopupProperty);

        public static void SetPopup(ButtonBase button, PopupBase value)
            => button.SetValue(PopupProperty, value);

        public static readonly DependencyProperty PopupProperty =
            DependencyProperty.RegisterAttached("Popup",
                                                typeof(PopupBase),
                                                typeof(PopupAttach),
                                                new PropertyMetadata(null,
                                                new PropertyChangedCallback((s, e) =>
                                                {
                                                    if (s is ButtonBase button && e.NewValue is PopupBase newPopup)
                                                    {
                                                        if (Application.Current.MainWindow.Content is Grid grid)
                                                        {
                                                            if (e.OldValue is PopupBase oldPopup)
                                                            {
                                                                grid.Children.Remove(oldPopup);
                                                            }

                                                            grid.Children.Add(newPopup);

                                                            button.Click -= buttonClick;
                                                            button.Click += buttonClick;
                                                        }
                                                        else
                                                        {
                                                            throw new Exception($"{nameof(Application.Current.MainWindow)} must have a root layout panel of type {nameof(Grid)} in order to use attachable Flyout.");
                                                        }

                                                        void buttonClick(object sender, RoutedEventArgs routedEventArgs)
                                                        {
                                                            newPopup.IsOpen = true;
                                                        }
                                                    }
                                                })));

    }
}

And then I have any UserControl I create inherit from PopupBase so my Popup UI's look sort of like this:

<local:PopupBase x:Class="RelayC.AddServer"
             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:local="clr-namespace:RelayC"
             mc:Ignorable="d"
             Width="500"
             Height="375">

UI CONTENT INSERTED HERE

</local:PopupBase>

The problem is when I want to attach it to a button, I have to do something like this:

   <Window.Resources>
        <local:AddServer Grid.Row="1" x:Key="ISERCpm"/>
    </Window.Resources>

in my MainWindow.xaml and then call it from a button using

<Button local:PopupAttach.Popup="{StaticResource ISERCpm}" />

Is there anyway to skip the Window Resource declaration and straight just call my PopupBase User Control?


Solution

  • PopupAttach.Popup is an attached dependency property. It is possible to use property element syntax instead of attribute syntax:

    <Button>
      <local:PopupAttach.Popup>
        <local:AddServer Grid.Row="1"/>
      </local:PopupAttach.Popup>
    </Button>