Home > OS >  C# wpf how bind parent dependecy property from inside dataTemplate
C# wpf how bind parent dependecy property from inside dataTemplate

Time:09-15

How binding user control dependecy property? I want ToolTip dependency property IsEnabled to bind from UserControl dependency property IsShowToolTip. I try RelativeSource, but this can't find source.

In UserControl i have:

        public bool IsShowToolTip
        {
            get { return (bool)GetValue(IsShowToolTipProperty); }
            set { SetValue(IsShowToolTipProperty, value); }
        }

        public static readonly DependencyProperty IsShowToolTipProperty =
            DependencyProperty.Register("IsShowToolTip", typeof(bool), typeof(SideMenuView), new PropertyMetadata(false));

In xaml:

<UserControl>
    <ItemsControl ItemsSource="{Binding Items}"
        ScrollViewer.VerticalScrollBarVisibility="Disabled"
        ScrollViewer.HorizontalScrollBarVisibility="Disabled">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Margin="0,0,0,12">
                    <RadioButton Content="{Binding MenuName}"
                                 GroupName="MainMenuButton"
                                 Command="{Binding ChangeViewCommand}">
                        <RadioButton .ToolTip>
                            <ToolTip Content="{Binding MenuName}" Placement="Right" HorizontalOffset="8"
                                     IsEnabled="{Binding IsShowToolTip, ?}">
                            </ToolTip>
                        <RadioButton.ToolTip>
                    <RadioButton >
                    <ListBox ItemsSource="{Binding SubItems}"
                             ScrollViewer.VerticalScrollBarVisibility="Disabled"
                             ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                             VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

CodePudding user response:

Give the UserControl a name,

<UserControl x:Name="MyUserControl">

Then reference it in the binding expression

IsEnabled="{Binding ElementName=MyUserControl, Path=IsShowToolTip}">

And Replace

new PropertyMetadata(false)

With

new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)

CodePudding user response:

Is there any way to make it work?

A bit of voodoo magic... :)

using System.Windows;
using System.Windows.Controls;

namespace Core2022.SO.JarosławPietras
{
    /// <summary>
    /// Логика взаимодействия для SideMenuView.xaml
    /// </summary>
    public partial class SideMenuView : UserControl
    {
        public SideMenuView()
        {
            InitializeComponent();
        }

        public bool IsShowToolTip
        {
            get { return (bool)GetValue(IsShowToolTipProperty); }
            set { SetValue(IsShowToolTipProperty, value); }
        }

        public static readonly DependencyProperty IsShowToolTipProperty =
            DependencyProperty.Register("IsShowToolTip", typeof(bool), typeof(SideMenuView), new PropertyMetadata(false));
    }

    public class SideMenuViewProxy : Freezable
    {
        public SideMenuView? SideMenuView
        {
            get { return (SideMenuView?)GetValue(SideMenuViewProperty); }
            set { SetValue(SideMenuViewProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SideMenuView.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SideMenuViewProperty =
            DependencyProperty.Register(nameof(SideMenuView), typeof(SideMenuView), typeof(SideMenuViewProxy), new PropertyMetadata(null));


        protected override Freezable CreateInstanceCore()
        {
            throw new System.NotImplementedException();
        }
    }
}
<UserControl x:Class="Core2022.SO.JarosławPietras.SideMenuView"
             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:Core2022.SO.JarosławPietras"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <local:SideMenuViewProxy
            x:Key="proxy"
            SideMenuView="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:SideMenuView}}}"/>
    </UserControl.Resources>
    <Grid Background="AliceBlue">
        <Grid.ToolTip>
            <ToolTip IsEnabled="{Binding SideMenuView.IsShowToolTip, Source={StaticResource proxy}}" >
                <StackPanel>
                    <Button Content="Some Button"/>
                    <TextBlock Text="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ToolTip}}}"/>
                </StackPanel>
            </ToolTip>
        </Grid.ToolTip>
        <CheckBox Content="on/off ToolTip"
                  IsChecked="{Binding IsShowToolTip, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:SideMenuView}}}"
                  VerticalAlignment="Top" HorizontalAlignment="Left"/>
    </Grid>
</UserControl>

P.S. This is one of the solutions. In addition to using StaticResource, you can also pass values through the DataContext. But it is usually occupied by the ViewModel. You can also make a proxy not entirely for the object, but only for the necessary properties.

Second Example

using System.Windows;
using System.Windows.Controls;

namespace Core2022.SO.JarosławPietras
{
    /// <summary>
    /// Логика взаимодействия для SideMenuView1.xaml
    /// </summary>
    public partial class SideMenuView1 : UserControl
    {
        public SideMenuView1()
        {
            InitializeComponent();
        }
    }

    public class MyProxy : Freezable
    {
        public bool IsToolTipEnabled
        {
            get { return (bool)GetValue(IsToolTipEnabledProperty); }
            set { SetValue(IsToolTipEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SideMenuView.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsToolTipEnabledProperty =
            DependencyProperty.Register(nameof(IsToolTipEnabled), typeof(bool), typeof(MyProxy), new PropertyMetadata(true));


        protected override Freezable CreateInstanceCore()
        {
            throw new System.NotImplementedException();
        }
    }

}
<UserControl x:Class="Core2022.SO.JarosławPietras.SideMenuView1"
             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:Core2022.SO.JarosławPietras"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <local:MyProxy x:Key="proxy"/>
    </UserControl.Resources>
    <Grid Background="AliceBlue">
        <Grid.ToolTip>
            <ToolTip IsEnabled="{Binding IsToolTipEnabled, Source={StaticResource proxy}}" >
                <StackPanel>
                    <Button Content="Some Button"/>
                    <TextBlock Text="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ToolTip}}}"/>
                </StackPanel>
            </ToolTip>
        </Grid.ToolTip>
        <CheckBox Content="on/off ToolTip"
                  IsChecked="{Binding IsToolTipEnabled, Source={StaticResource proxy}}"
                  VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </Grid>
</UserControl>
  • Related