[WPF XAML] Can I bind the property of my own UserControl?

2 minute read

I was addicted to writing WPF XAML, so make a note.
(Added on August 12, 2020) We are using .NET Framework 4.8.

I wanted to bind Visibility

I wrote the code to bind the visibility of my own UserControl.
I am trying to be able to change the visibility of MyUserControl through MyUserControlVisibility.

MainWindow.xaml


<Window x:Name="Test" x:Class="MyNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyNamespace"
        mc:Ignorable="d"
        Title="test">
    <Window.DataContext>
        <local:MainWindowUserControl/>
    </Window.DataContext>
    <local:MyUserControl x:Name="MyControl1" Visibility="{Binding MyUserControlVisibility, Mode=TwoWay}"/>
</Window>

C#:MainWindow.xaml.cs


//using is omitted. I'm using Prism
namespace MyNamespace
{
    public class MainWindowViewModel : BindableBase
    {
        private Visibility _MyUserControlVisibility = Visibility.Hidden;
        public Visibility MyUserControlVisibility
        {
            get { return _MyUserControlVisibility; }
            set { SetProperty(ref _MyUserControlVisibility, value); }
        }
    }
    
    public class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

However, this didn’t work and was ignored.

Try rewriting to DataTrigger

I think that it will work if I ignite it with DataTrigger, so I will rewrite it.

MainWindow.xaml


<Window x:Name="Test" x:Class="MyNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyNamespace"
        mc:Ignorable="d"
        Title="test">
    <Window.DataContext>
        <local:MainWindowUserControl/>
    </Window.DataContext>
    <local:MyUserControl x:Name="MyControl1">
        <local:MyUserControl.Style>
            <Style TargetType="local:MyUserControl"> <!--It does not change even if TargetType is UserControl-->
                <Setter Property="Visibility" Value="Visible"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding MyUserControlVisibility}" Value="Hidden">
                        <Setter Property="Visibility" Value="Hidden"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </local:MyUserControl.Style>
    </local:MyUserControl>
</Window>

However, it sank. It will be ignored again.

(Solution) Put in Grid

Put the desired UserControl in the Grid and try binding the Grid’s Visibility.

MainWindow.xaml


<Window x:Name="Test" x:Class="MyNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyNamespace"
        mc:Ignorable="d"
        Title="test">
    <Window.DataContext>
        <local:MainWindowUserControl/>
    </Window.DataContext>
    <Grid Visibility="{Binding MyUserControlVisibility, Mode=TwoWay}">
        <local:MyUserControl x:Name="MyControl1"/>
    </Grid>
</Window>

With this, it worked as desired. However, sandwiching it between Grids … I hate it because it feels like a waste of memory.

2020.8.12 Addendum …… (Solution) Bind on the side that defines UserControl

After that, I tried binding Visibility in the XAML that defines MyUserControl.

MyUserControl.xaml


<UserControl x:Class="MyNamespace.MyUserControl"
             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:MyNamespace"
             mc:Ignorable="d"
             Visibility="{Binding Visibility}"/>
    <UserControl.DataContext>
        <local:MyUserControlViewModel/>
    </UserControl.DataContext>
</UserControl>

C#:MyUserControl.xaml.cs


//using is omitted
namespace MyNamespace
{
    public class MyUserControlViewModel : BindableBase
    {
        private Visibility _Visibility = Visibility.Hidden;
        public Visibility Visibility
        {
            get { return _Visibility; }
            set { SetProperty(ref _Visibility, value); }
        }
    }
    
    public class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }
    }
}

C#:MainWindow.xaml.cs


//using is omitted
namespace MyNamespace
{
    public class MainWindowViewModel
    {
        private MyUserControlViewModel _MyControl1VM;
        public MyUserControlViewModel MyControl1VM
        {
            get { return _MyControl1VM; }
            set { SetProperty(ref _MyControl1VM, value); }
    }
    
    public class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            MainWindowViewModel VM = DataContext;
            VM.MyControl1VM = MyControl1.DataContext;
        }
    }
}

It worked fine with this.
Being able to define the Visibility property in the ViewModel of MyUserControl is also delicious in terms of object orientation. I think this is probably the most beautiful. ** I'm sorry I'm lying (crying) **
I changed the dataContext to be set in XAML and made it a little slimmer. (Added on August 13, 2020)

At the end

I can’t bind well only to my own UserControl, is it a bug? Or is it a specification?

** WPF’s XAML is basically a specification that does not throw an exception even if an error occurs related to Binding, and only leaves an output log when debugging is executed. ** It’s a good error, so I’d like you to insist a little more. How about MS?
(Corrected on August 12, 2020)