[WPF XAML] Can I bind the property of my own UserControl?
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)