views:

42

answers:

3

I've some simple code below that uses a ToggleButton.IsChecked property to set the Visibility of a TextBlock. It works fine. Since this doesn't quite fit in with my program's structure, I'm trying to bind the visibility of another TextBlock to a DependencyProperty of "this". It compiles fine, but it produces no effect. I'm doing something wrong, just not sure what.

XAML

<Window x:Class="ToggleButtonTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Width="200" Height="100">
<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<StackPanel>
    <ToggleButton x:Name="toggleButton" Content="Toggle"
                  IsChecked="True" Checked="toggleButton_Checked"/>
    <TextBlock Text="Some Text"
               Visibility="{Binding IsChecked, 
               ElementName=toggleButton,
               Converter={StaticResource BooleanToVisibilityConverter}}"/>
    <TextBlock Text="More Text"
               Visibility="{Binding ShowMoreText, 
               ElementName=this, 
               Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
</Window>

C#

using System.Windows;

namespace ToggleButtonTest
{
    public partial class MainWindow : Window
    {
        static MainWindow()
        {
            FrameworkPropertyMetadata meta = 
                new FrameworkPropertyMetadata(true,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault);

            ShowMoreTextProperty = 
                DependencyProperty.Register("ShowMoreText", 
                typeof(bool), typeof(MainWindow), meta);
        }

        public MainWindow()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty ShowMoreTextProperty;
        public bool ShowMoreText
        {
            get
            {
                return (bool)GetValue(ShowMoreTextProperty);
            }
            set
            {
                SetValue(ShowMoreTextProperty, value);
            }
        }

        private void toggleButton_Checked(object sender, RoutedEventArgs e)
        {
            ShowMoreText = toggleButton.IsChecked.Value;
        }
    }
}

Edit:

Having had this answered, I want to post my working code...

XAML

<Window x:Class="ToggleButtonTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Width="200" Height="100"
    Name="thisWindow">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    </Window.Resources>
    <StackPanel>
        <ToggleButton x:Name="toggleButton" 
                Content="Toggle"
                IsChecked="{Binding Path=ShowMoreText, ElementName=thisWindow}"/>
        <TextBlock Text="More Text"
                   Visibility="{Binding Path=ShowMoreText, 
                   ElementName=thisWindow,
                   Converter={StaticResource BooleanToVisibilityConverter}}"/>
    </StackPanel>
</Window>

C#

using System.Windows;

namespace ToggleButtonTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty ShowMoreTextProperty =
            DependencyProperty.Register("ShowMoreText", typeof(bool),
            typeof(MainWindow), new FrameworkPropertyMetadata(true,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        public bool ShowMoreText
        {
            get
            {
                return (bool)GetValue(ShowMoreTextProperty);
            }
            set
            {
                SetValue(ShowMoreTextProperty, value);
            }
        }
    }
}
+1  A: 

Give your Window a name and set the ElementName to that name, instead of using "this".

Russ
Thanks, as well.
Nate
+4  A: 

ElementName must really be an element name. this doesn't fly. Fortunately, you do have an element of type MainWindow here with a ShowMoreText property: the root Window element.

Give the Window a name and use that as ElementName, as below:

<Window x:Class="ToggleButtonTest.MainWindow"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Title="MainWindow" Width="200" Height="100"
     x:Name="thisWindow">
<Window.Resources>
     <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<StackPanel>
     <ToggleButton x:Name="toggleButton" Content="Toggle"
                        IsChecked="True" Checked="toggleButton_Checked"/>
     <TextBlock Text="Some Text"
                    Visibility="{Binding IsChecked, 
                    ElementName=toggleButton,
                    Converter={StaticResource BooleanToVisibilityConverter}}"/>
     <TextBlock Text="More Text"
                    Visibility="{Binding ShowMoreText, 
                    ElementName=thisWindow, 
                    Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
</Window>

Note that you can do the same using RelativeSource Self, but I prefer the method above.

Jay
+1. It should also be mentioned that using "this" as the ElementName argument won't refer to the same "this" as C# does.
rossisdead
Thanks! That makes sense now. I hadn't considered giving the Window a name. Unfortunately, it doesn't seem to have solved the problem. Still looking at it...
Nate
+2  A: 

The way you have it set up currently won't ever set ShowMoreText to false. The Checked handler will only be called when the ToggleButton's IsChecked changes from false to true. To also go the other way you need a handler for Unchecked as well. The best way to handle this situation would be to instead set a Binding on the ToggleButton that will do both without any event handlers (using Jay's changes):

IsChecked="{Binding Path=ShowMoreText, ElementName=thisWindow}"
John Bowen
Excellent. I wasn't paying attention that the Checked event only happened when it was true. Between your answer and Jay's I have been able to solve this. Thank you.
Nate