2

I am trying to bind a normal property of AvalonDock,

xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock"

 <xcad:LayoutAnchorable Title="Folder" CanHide="{Binding IsHideExplorerView}">
      <Views:ExplorerView DataContext="{Binding ExplorerViewModel}"/>
 </xcad:LayoutAnchorable>

Here CanHide is a Normal property, if trying to bind will throw the exception like

A 'Binding' can only be set on a DependencyProperty of a DependencyObject.

My question is, Is it possible any way to make a normal property to override DependencyProperty to make it Bindable.

Edit

Added a class which inherit LayoutAnchorable but PropertyChangedCallback of DependencyProperty Never calls.

 public class ExtendedAnchorableItem : LayoutAnchorable
 {
     public static readonly DependencyProperty IsCanHideProperty =
        DependencyProperty.RegisterAttached("IsCanHide", typeof(bool), typeof(ExtendedAnchorableItem),
            new FrameworkPropertyMetadata((bool)false,
                new PropertyChangedCallback(OnCanHideChanged)));
    public bool IsCanHide
    {
        get { return (bool)GetValue(IsCanHideProperty); }
        set { SetValue(IsCanHideProperty, value);

this.IsVisible = value; // No effect.

             }
    }
    private static void OnCanHideChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((ExtendedAnchorableItem)d).Hide();
    }
  }

XAML

 <xcad:LayoutAnchorablePane>
     <Utility:ExtendedAnchorableItem IsCanHide="{Binding IsHideExplorer}">
         <Views:ExplorerView DataContext="{Binding ExplorerViewModel}"/>
      </Utility:ExtendedAnchorableItem>
 </xcad:LayoutAnchorablePane>

Similarly i have tried creating an AttachedProperty which can hook it to LayoutAnchorable but PropertyChangedCallback Never get called click here for a new question i have posted.

Any Help guys ?

Community
  • 1
  • 1
Abin
  • 2,868
  • 1
  • 23
  • 59

3 Answers3

1

I did and example previously in my case i need to create new button with 2 images one when the button is available and the other one when it's disabled, to do that first i created new user control named "MyButton" my xaml was like this

<Button ToolTip="{Binding ButtonLabel,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor},UpdateSourceTrigger=PropertyChanged}" 
                Command="{Binding ButtonCommand,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor},UpdateSourceTrigger=PropertyChanged}"
                Cursor="Hand" VerticalAlignment="Center" >
            <Button.Template>
                <ControlTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="45"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Image Name="ButtonImage" IsEnabled="{Binding Path=IsEnabled,RelativeSource={RelativeSource AncestorType=Button,Mode=FindAncestor}}"  >
                            <Image.Style>
                                <Style TargetType="{x:Type Image}">
                                    <Style.Triggers>
                                        <Trigger Property="IsEnabled" Value="True">
                                            <Setter Property="Source" Value="{Binding ActiveImage,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor},UpdateSourceTrigger=PropertyChanged}"/>
                                        </Trigger>
                                        <Trigger Property="IsEnabled" Value="False">
                                            <Setter Property="Source" Value="{Binding DeactiveImage,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor},UpdateSourceTrigger=PropertyChanged}"/>
                                        </Trigger>
                                    </Style.Triggers>
                                </Style>
                            </Image.Style>
                        </Image>
                        <Label Name="LabelContent" Content="{Binding ButtonLabel,RelativeSource={RelativeSource AncestorType=UserControl,Mode=FindAncestor},UpdateSourceTrigger=PropertyChanged}" 
                       Grid.Column="1" IsEnabled="{Binding Path=IsEnabled,RelativeSource={RelativeSource AncestorType=Button,Mode=FindAncestor}}" VerticalContentAlignment="Center"  />
                    </Grid>
                </ControlTemplate>
            </Button.Template>
        </Button> 

then i added dependency Properties for ActiveImage and DeactiveImage using this code

public static  DependencyProperty activeImage =
           DependencyProperty.Register("ActiveImage", typeof(type of this property like  "string"), typeof(type of the custom control that you need like  "MyButton"), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

        public string ActiveImage
        {
            get { return (string)GetValue(activeImage); }
            set { SetValue(activeImage, value); }
        }

then i used this new control in my project

<custom:MyButton ButtonCommand="{Binding DecreaseImagesCount}" ButtonLabel="ZoomIn" ActiveImage="/Images/ActiveImages/ZoomIn.png" DeactiveImage="/Images/GrayImages/ZoomIn.png" 
                                             Grid.Column="2" Margin="3,4" />

notice that i can do binding the path for Button Image now

j.kahil
  • 276
  • 5
  • 16
  • Can you explain it how to go ahead with AvalonDock, Do i need to create a new class which will extend the `LayoutAnchorable` and then add a `Dependency Property`. – Abin Aug 31 '15 at 18:51
  • you can create a new user control in this user control add AvalonDock in xaml and then add this dependency property, if you face any issue i can send to an example – j.kahil Aug 31 '15 at 18:54
  • Appreciate if you can add the example to the answer. – Abin Aug 31 '15 at 18:56
  • I understand what you have did, but my question here is i have a `Normal Property` called `CanHide`, i cant bind that property as it is Normal Property, how can i make it `Bindable`. i am not clear form your example where you did that scenario. – Abin Aug 31 '15 at 19:17
  • try to create new control and use avalondock inside it and give this control name then create new dependency property and when it change you can modify the "canHide" value from code behind, form outside you will use your new property which is bindable , I hope it's clear for you :) – j.kahil Aug 31 '15 at 19:30
  • +1 for good solution. but need a try making it working. when it works i will accept the answer. Thanks for helping out. – Abin Aug 31 '15 at 21:58
  • One doubt `"when it change you can modify the "canHide" value"` where will i write the code for this ? – Abin Aug 31 '15 at 22:14
  • Here you need to modify the code: public string ActiveImage { get { return (string)GetValue(activeImage); } set { SetValue(activeImage, value);avalonDock1.CanHide = value; } } – j.kahil Sep 01 '15 at 04:54
  • I have tried the way you have suggested. but some how i cant make a user control for my `LayoutAnchorable` but created a class which inherits `LayoutAnchorable` and added the `DependencyProperty` as suggested. but `PropertyChangedCallback` never get called. Look at my question for edited part will give more clarity what i did. – Abin Sep 02 '15 at 15:47
  • i think you don't have to call callback, you can just add one line code to set part for "IsCanHide" Property in the new class and use an element name like this avalonDock1.CanHide = value. Have you tried this approach ? – j.kahil Sep 03 '15 at 07:51
  • I have tried that to no impact on it. Check my edit to see what i did. – Abin Sep 03 '15 at 11:48
  • I think this.IsVisibile it will not work because "this" it not related to your custom control try again but using control name instead of this, i mean add name property in your custom control and then use the same name in code behind – j.kahil Sep 03 '15 at 16:57
1

If it is enough for you to just set that property from your view model then you could use an attached behavior. Just create a new class and add an attached property like this (I did not really test this, since I actually do not have AvalonDock at hand, but you should get the idea):

public class YourBehavior
{
    public static readonly DependencyProperty YourCanHideProperty = DependencyProperty.RegisterAttached(
                "YourCanHide",
                typeof(bool),
                typeof(LayoutAnchorable),
                new PropertyMetadata(YourCanHidePropertyChanged));

    private static void YourCanHidePropertyChanged(
        DependencyObject dependencyObject,
        DependencyPropertyChangedEventArgs e)
    {
        LayoutAnchorable control = dependencyObject as LayoutAnchorable;
        if (control != null)
        {
            control.CanHide = e.NewValue as bool;
        }
    }

    public static bool GetYourCanHideProperty(LayoutAnchorablewindow)
    {
        return window.GetValue(YourProperty) as bool?;
    }

    public static void SetYourCanHideProperty(LayoutAnchorable control, bool value)
    {
        window.SetValue(YourProperty, value);
    }
}

Now you should be able to use that behavior like this:

<xcad:LayoutAnchorable Title="Folder" namespacealias:YourBehavior.YourCanHideProperty="{Binding IsHideExplorerView}"/>

If you want to have it working in both directions just check out the attached Blend behaviors.

E812
  • 21
  • 7
  • Good I will have a look at it and let you know if it works. Thanks. – Abin Sep 01 '15 at 20:36
  • I have tried using an `AttachedProperty` like you mentioned, but the `PropertyChangedCallback` Never get called, I have attached the behavior to a `DockPanel` it works and even i have attached to `DockingManager` of AvalonDock it works but not in `LayoutAnchorable` any suggestion? – Abin Sep 02 '15 at 03:54
0

Yes, you can do it.. you need to implement INotifypropertyChanged interface and raise a ProprtyChanged Event inside the property setter. After changing the property to a DependencyProperty, you will get the notification mechanism, so the property change is propagated to the target (in this case xcad) .

you can find lot of examples implementing the INotifyPropertyChanged..

Hussain Patel
  • 460
  • 3
  • 10
  • 24