PropertyChanged and IValueConverter

262 Views Asked by At

I need that when clicking on UserControl in TextBlock Visibility changed depending on what value is IsChecked

I wanted to make my checkbox but I ran into such a problem. System.NullReferenceException: "The object reference does not point to an instance of the object." in the OnPropertyChanged method. The logic of this control is that when you click Visibility on it, TextBlock should become either Hidden or Visible (depends on IsChecked value). If I do not write OnPropertyChanged ("IsChecked"); then when the click does not crash, but nothing happens.

UserCheckBox.xaml.cs

public partial class UserCheckBox : UserControl
{
    public UserCheckBox()
    {
        InitializeComponent();
        DataContext = this;
        MouseUp += delegate (object sender, MouseButtonEventArgs e)
        {
            this.IsChecked = true;
        };
    }

    private bool _IsChecked = false;
    public bool IsChecked
    {
        get { return _IsChecked; } private set { _IsChecked = value; OnPropertyChanged("IsChecked"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

UserCheckBox.xaml

<UserControl x:Class="COP.UserCheckBox"
         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:COP"
         mc:Ignorable="d" 
         d:DesignHeight="30" d:DesignWidth="30" Background="#707070" Name="mainCheckBox">
<UserControl.Resources>
    <local:VisibilityConvert x:Key="Convert"></local:VisibilityConvert>
</UserControl.Resources>
<Border BorderThickness="2" BorderBrush="Black">
    <Grid>        
    <TextBlock FontFamily="Segoe UI Symbol" Text="&#xE10B;" Visibility="{Binding ElementName=mainCheckBox, Path=IsChecked, Converter={StaticResource Convert}}"></TextBlock>
</Grid>
</Border>

VisibilityConvert.cs

class VisibilityConvert : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (bool)value == true ? Visibility.Visible : Visibility.Hidden;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
1

There are 1 best solutions below

3
Shahin Dohan On BEST ANSWER

Your UserControl has to use the INotifyPropertyChanged interface, otherwise WPF doesn't know to listen to this class.

Do this:

public partial class UserCheckBox : UserControl, INotifyPropertyChanged

Also, your IsChecked setter is private when it should be public, otherwise you can't set the property.

Another thing to note, is that you can't use Binding on this property because it's not a Dependency Property so you can only set it in XAML like so IsChecked="True". You might want to create a Dependency Property instead, read this article.

EDIT:

Since I had IsChecked="True" while testing your code OP, I forgot that you also need to subscribe to a left mouse click event, do this on your UserControl XAML:

MouseLeftButtonDown="OnMouseLeftButtonDown" Background="Transparent"

Then create the method in your UserControl.xaml.cs:

private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    IsChecked = !IsChecked;
}

The reason for the Transparent background is to enable click events on the entire area of the UserControl.

All of this being said, I highly suggest you ditch this whole thing. You're much better off learning how to style an existing Checkbox control rather than creating your own.