简体   繁体   中英

{Binding elementName...} failing

I have created an dummy window with

  • a checkbox
  • a Button
  • a Button inside a custom UserControl

Both Buttons start out Blue, and when the checkbox is checked, they should both turn orange. However, the one inside the user control seems to be ignoring the checkbox. Why is it failing, and how can I get around this?

The UserControl I want to insert:

<UserControl x:Class="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"
       mc:Ignorable="d"
       d:DesignHeight="300" d:DesignWidth="300"
       DataContext="{Binding RelativeSource={RelativeSource Self}}"


       <Grid>
            <!--MyContent is a dependency property in UserControl1's code behind-->
            <ContentControl Content="{Binding MyContent}">      
       </Grid>
</UserControl>

The Main Window:

<Window x:Class="WpfApplication11.MainWindow"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="MainWindow" Height="350" Width="525">
       <Window.Resources>
           <ResourceDictionary>

               <Style TargetType="Button">
                   <Setter Property="Background" Value="Cyan"/>
                   <Style.Triggers>
                       <DataTrigger Binding="{Binding ElementName=myCheckbox, Path=isChecked}" Value="True">
                           <Setter Property="Background" Value="Orange/>
                       </DataTrigger>
                   </Style.Triggers>
               </Style>

               <Button x:Key="Button1"  Content="Button1"/>
               <Button x:Key="Button2"  Content="Button2"/>

           </ResourceDictionary>
       </Window.Resources>

       <Grid>
           <Grid.RowDefinitions>
               <RowDefinition Height="1*"/>
               <RowDefinition Height="1*"/>
               <RowDefinition Height="1*"/>
           </Grid.RowDefinitions>

           <CheckBox x:Name = "myCheckBox" Content="Turn Orange" Grid.Row="0"/>

           <!--This updates when I check myCheckBox-->        
           <ContentControl Content = "{StaticResource Button1}" Grid.Row="2"/>

           <!--This does NOT update when I check myCheckBox-->
           <test:UserControl1 MyContent="{StaticResource Button2}" Grid.Row="2"/>

       </Grid>
</Window>

Why is it failing

Because there is no CheckBox named "myCheckBox" in the UserControl. The CheckBox in the parent window resides in another naming scope so binding to an ElementName won't work here.

How can I get around this?

Learn and implement MVVM design pattern: https://msdn.microsoft.com/en-us/library/hh848246.aspx . It is the recommended design pattern to use when developing XAML based UI applications.

Create view model class that holds the current status of the CheckBox:

public class ViewModel : INotifyPropertyChanged
{
    private bool _isChecked;
    public bool IsChecked
    {
        get { return _isChecked; }
        set { _isChecked = value; OnPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

And set the DataContext of the window to an instance of this and bind to its IsChecked property instead of binding directly to the CheckBox:

<Window ...>
    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="Cyan"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsChecked}" Value="True">
                    <Setter Property="Background" Value="Orange"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <Button x:Key="Button1"  Content="Button1"/>
        <Button x:Key="Button2"  Content="Button2"/>
    </Window.Resources>
    <Window.DataContext>
        <test:ViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>

        <CheckBox x:Name ="myCheckBox" Content="Turn Orange" Grid.Row="0" IsChecked="{Binding IsChecked}"/>

        <ContentControl Content = "{StaticResource Button1}" Grid.Row="1"/>

        <test:UserControl2 MyContent="{StaticResource Button2}" Grid.Row="2"/>

    </Grid>
</Window>

The UserControl should inherit the DataContext of the parent window so don't set the DataContext property explicitly in UserControl1.xaml:

<UserControl x:Class="WpfApplication11.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:WpfApplication2"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <ContentControl Content="{Binding MyContent, RelativeSource={RelativeSource AncestorType=UserControl}}" />
    </Grid>
</UserControl>

You can't reference myCheckBox from the style, those are two different scopes. Plus the style is targeting a button, but the control is a Window. You'd have to put all the controls within the style in the control template.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM