Hi Steve,
I'm back with the promised example: It Shows 3 different approaches (a 4th would be possible here with
behaviors
, but I don't want to confuse you ;)
I suggest put this in a new WPF application Project and let it run:
first you need a CustomControl:
public class CustomControl : Control
{
static CustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
}
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set
{
SetValue(IsCheckedProperty, value);
}
}
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool), typeof(CustomControl), new PropertyMetadata(false));
}
and in generic.xaml (the file should be generated inside a Folder named "Themes" if you add a customcontrol to a WPF Project).
esourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp4">
<Style TargetType="{x:Type local:CustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel>
<TextBlock> UserControl - a composition of existing Controls</TextBlock>
<CheckBox Content="I represent the checked state" IsChecked="{TemplateBinding IsChecked}"></CheckBox>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
second a UserControl:
<UserControl x:Class="WpfApp4.UserControl1"
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:WpfApp4"
mc:Ignorable="d">
<StackPanel Background="White" Width="301">
<TextBlock> UserControl - a composition of existing Controls</TextBlock>
<CheckBox x:Name="checkbox" Content="I represent the checked state"></CheckBox>
</StackPanel>
</UserControl>
public partial class UserControl1 : UserControl
{
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set
{
SetValue(IsCheckedProperty, value);
checkbox.IsChecked = value;
}
}
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool), typeof(UserControl1), new PropertyMetadata(false));
public UserControl1()
{
InitializeComponent();
}
}
third a ViewModel
public class ViewModel : INotifyPropertyChanged
{
bool m_bIsChecked;
public event PropertyChangedEventHandler PropertyChanged;
public bool IsChecked
{
get { return m_bIsChecked; }
set
{
if (m_bIsChecked != value)
{
m_bIsChecked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked)));
}
}
}
}
and a test-window (I used pre-generated MainWindow) to Show the use:
<Window x:Class="WpfApp4.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:WpfApp4"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:UserControl1 x:Name="usercontrol1">
</local:UserControl1>
<local:CustomControl x:Name="customcontrol">
</local:CustomControl>
<CheckBox x:Name="checkbox" Content="I'm cooler - using MVVM and let the WPF do the rest" IsChecked="{Binding IsChecked}"></CheckBox>
<Button Content="Set checked state by code" Click="Button_Click"> </Button>
</StackPanel>
</Window>
with Code behind:
public partial class MainWindow : Window
{
ViewModel m_viewmodel = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = m_viewmodel;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
usercontrol1.IsChecked = !usercontrol1.IsChecked;
customcontrol.IsChecked = !customcontrol.IsChecked;
checkbox.IsChecked = !checkbox.IsChecked;
}
}
So what we see here:
1. a UserControl is just a bunch of other Controls + some DependencyProperties - nothing is done with binding (because you don't Control the DataContext)
2. a CustomControl with a generic theme and TemplateBinding - better for your case I'd say.
3. Don't create any controls use a pattern to bind data - MVVM - we just set the ViewModel as DataContext for the window and let the binding-mechanism do the rest.
I would always go for approach 3 nowadays, sometimes you will still need approach 2, Approach 1 - as you found out for yourself is "not so good", because it's not so easys to make it right without a lot of knowledge of WPF (same is true for Approach 2).
I hope this helps you to find your current Problem.
Kind regards
Johannes