How to set WPF behavior property using a data trigger - c#

I am trying to set a WPF behavior property using a style in the following way:
<StackPanel>
<CheckBox Name="IsFemaleChkBox" Content="Is Female ?" />
<TextBlock>
<Hyperlink> <!--setting property directly like this: local:MyHyperLinkBehavior.Salutation="Mr." isn't working either-->
<TextBlock Text="My Hyperlink"/>
<Hyperlink.Style>
<Style TargetType="Hyperlink">
<Setter Property="local:MyHyperLinkBehavior.Salutation" Value="Mr." />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=IsFemaleChkBox}" Value="True">
<Setter Property="local:MyHyperLinkBehavior.Salutation" Value="Miss" />
</DataTrigger>
</Style.Triggers>
</Style>
</Hyperlink.Style>
</Hyperlink>
</TextBlock>
</StackPanel>
And the behavior class code is this:
class MyHyperLinkBehavior : Behavior<Hyperlink>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Click += AssociatedObject_Click;
}
public static bool GetIsFemale(DependencyObject obj)
{
return (bool)obj.GetValue(IsFemaleProperty);
}
public static void SetIsFemale(DependencyObject obj, bool value)
{
obj.SetValue(IsFemaleProperty, value);
}
// Using a DependencyProperty as the backing store for IsFemale. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsFemaleProperty =
DependencyProperty.RegisterAttached("IsFemale", typeof(bool), typeof(MyHyperLinkBehavior), new PropertyMetadata(false));
public static string GetSalutation(DependencyObject obj)
{
return (string)obj.GetValue(SalutationProperty);
}
public static void SetSalutation(DependencyObject obj, string value)
{
obj.SetValue(SalutationProperty, value);
}
// Using a DependencyProperty as the backing store for Salutation. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SalutationProperty =
DependencyProperty.RegisterAttached("Salutation", typeof(string), typeof(MyHyperLinkBehavior), new PropertyMetadata(default(string)));
void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e)
{
MessageBox.Show(Convert.ToString(GetValue(SalutationProperty)));
}
}
I can't figure out why this is not working. Or setting a behavior's property using style isn't valid at all ? What is the other way round, if this is not valid.

There are two types of behaviors in WPF:
System.Windows.Interactivity Behaviors, called also Blend Behaviours
These behaviours are classes inherited from System.Windows.Interactivity.Behavior and you can use them by adding to used them by Adding it to Behaviours collection, e.g:
<Rectangle>
<i:Interaction.Behaviors>
<ei:MouseDragElementBehavior />
</i:Interaction.Behaviors>
</Rectangle>
notice, that these behaviors does not have any custom attached properties. OnAttached and OnDetached methods are automatically called.
Pros: Easy to implement
Cons: Does not work with styles (however, it works with ControlTemplates and DataTemplates)
Behaviors implemented as Custom Attached Property
In these behaviors the logic defined in PropertyChangedCallback of the custom attached property.
public static readonly DependencyProperty SalutationProperty =
DependencyProperty.RegisterAttached("Salutation",
typeof(string),
typeof(MyHyperLinkBehavior),
new PropertyMetadata(OnSalutationPropertyChanged));
private static void OnSalutationPropertyChanged(object sender,
DependencyPropertyChangedEventArgs e)
{
//attach to event handlers (Click, Loaded, etc...)
}
Pros: Can be defined in styles, easier to use
Cons: Chatty code, a little more difficult to implement
You are mixing those two types of behaviors together. Choose one and use it! Since you want to use it in style, you shoud choose behavior implemented as custom attached property

I got it working, it was a small miss by me.
I forgot to set the behavior on the hyperlink.
I need to get the property of the attachedObject and not of the
behavior.
Following code works fine:
<StackPanel>
<CheckBox Name="IsFemaleChkBox" Content="Is Female ?" />
<TextBlock>
<Hyperlink>
<TextBlock Text="My Hyperlink"/>
<i:Interaction.Behaviors> <!--Missed setting behavior-->
<local:MyHyperLinkBehavior />
</i:Interaction.Behaviors>
<Hyperlink.Style>
<Style TargetType="Hyperlink">
<Setter Property="local:MyHyperLinkBehavior.Salutation" Value="Mr." />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=IsFemaleChkBox}" Value="True">
<Setter Property="local:MyHyperLinkBehavior.Salutation" Value="Miss" />
</DataTrigger>
</Style.Triggers>
</Style>
</Hyperlink.Style>
</Hyperlink>
</TextBlock>
</StackPanel>
And the behavior:
class MyHyperLinkBehavior : Behavior<Hyperlink>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Click += AssociatedObject_Click;
}
public static bool GetIsFemale(DependencyObject obj)
{
return (bool)obj.GetValue(IsFemaleProperty);
}
public static void SetIsFemale(DependencyObject obj, bool value)
{
obj.SetValue(IsFemaleProperty, value);
}
// Using a DependencyProperty as the backing store for IsFemale. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsFemaleProperty =
DependencyProperty.RegisterAttached("IsFemale", typeof(bool), typeof(MyHyperLinkBehavior), new PropertyMetadata(false));
public static string GetSalutation(DependencyObject obj)
{
return (string)obj.GetValue(SalutationProperty);
}
public static void SetSalutation(DependencyObject obj, string value)
{
obj.SetValue(SalutationProperty, value);
}
// Using a DependencyProperty as the backing store for Salutation. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SalutationProperty =
DependencyProperty.RegisterAttached("Salutation", typeof(string), typeof(MyHyperLinkBehavior), new PropertyMetadata(default(string)));
void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e)
{
// Changing "GetValue(SalutationProperty)" to "this.AssociatedObject.GetValue(SalutationProperty)" works
MessageBox.Show(Convert.ToString(this.AssociatedObject.GetValue(SalutationProperty)));
}
}

Related

An style for a tooltip only works partially

I would like to have an standar tooltip for all the controls, setting the initial delay, the show delay and that it can be shown when is not enabled. In the control I only would need to set the text of the tooltip in each case.
I have this style:
<sys:Int32 x:Key="TooltipInitialShowDelay">2000</sys:Int32>
<sys:Int32 x:Key="TooltipInitialShowDelayLong">5000</sys:Int32>
<sys:Int32 x:Key="TooltipDisplayTime">60000</sys:Int32>
<Style TargetType="ToolTip" x:Key="ToolTipDefaultStyle">
<Setter Property="ToolTipService.ShowOnDisabled" Value="true"/>
<Setter Property="ToolTipService.InitialShowDelay" Value="{StaticResource TooltipInitialShowDelay}"/>
<Setter Property="ToolTipService.ShowDuration" Value="{StaticResource TooltipDisplayTime}"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding PlacementTarget.(dp:ToolTipDependencyProperty.Texto), RelativeSource={RelativeSource AncestorType=ToolTip}}" MaxWidth="400" TextWrapping='Wrap' />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I have this dependency properties:
public static class ToolTipDependencyProperty
{
#region Texto
public static readonly DependencyProperty TextoProperty =
DependencyProperty.RegisterAttached(
"Texto",
typeof(string),
typeof(ToolTipDependencyProperty));
public static string GetTexto(DependencyObject obj)
{
return (string)obj.GetValue(TextoProperty);
}
public static void SetTexto(DependencyObject obj, string value)
{
obj.SetValue(TextoProperty, value);
}
#endregion Texto
#region InitialShowDelay
public static readonly DependencyProperty InitialShowDelayProperty =
DependencyProperty.RegisterAttached(
"InitialShowDelay",
typeof(int),
typeof(ToolTipDependencyProperty));
public static int GetInitialShowDelay(DependencyObject obj)
{
return (int)obj.GetValue(InitialShowDelayProperty);
}
public static void SetInitialShowDelay(DependencyObject obj, int value)
{
obj.SetValue(InitialShowDelayProperty, value);
}
#endregion InitialShowDelay
#region ShowDuration
public static readonly DependencyProperty ShowDurationProperty =
DependencyProperty.RegisterAttached(
"ShowDuration",
typeof(int),
typeof(ToolTipDependencyProperty));
public static int GetShowDuration(DependencyObject obj)
{
return (int)obj.GetValue(ShowDurationProperty);
}
public static void SetShowDuration(DependencyObject obj, int value)
{
obj.SetValue(ShowDurationProperty, value);
}
#endregion ShowDuration
}
And this is my button:
<Button Name="btnBuscar" Content="Buscar" Command="{Binding BuscarCommand}"
IsEnabled="{Binding BuscarIsEnabled}"
dp:ToolTipDependencyProperty.Texto="{Binding BuscarToolTip}">
<Button.ToolTip>
<ToolTip Style="{StaticResource ToolTipDefaultStyle}"/>
</Button.ToolTip>
</Button>
The problem is that the text is ahown, but only when the button is enabled. And also the initial show delay and show duration is the standard duration, not the values that I want to use.
However, if in the control I set the ToolTip.Service variables, it works.
How could I set the duration in the style?
Thanks.
The ToolTipService attached properties need to be set on the element that owns the tooltip, not the tooltip itself.
You'll need to create a style for Button, or FrameworkElement.

How to use another dependency property as a fallback value

I am creating a user control which is a toggle button with image. I have separate dependency properties for image when the toggle button is checked and when the toggle button is not checked.
Xaml:
<ToggleButton IsChecked="{Binding Checked, Mode=TwoWay}">
<Image>
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="{Binding CheckedImage}"></Setter>
<DataTrigger Binding="{Binding IsChecked}" Value="False">
<Setter Property="Source" Value="{Binding UncheckedImage}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ToggleButton>
Code behind:
public partial class ImageToggleButton : UserControl
{
public ImageToggleButton()
{
InitializeComponent();
this.DataContext = this;
}
public bool Checked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("Checked", typeof(bool), typeof(ImageToggleButton), null);
public ImageSource CheckedImage
{
get { return (ImageSource)base.GetValue(TrueStateImageProperty); }
set { base.SetValue(TrueStateImageProperty, value); }
}
// Using a DependencyProperty as the backing store for TrueStateImage. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TrueStateImageProperty =
DependencyProperty.Register("CheckedImage", typeof(ImageSource), typeof(ImageToggleButton), null);
public ImageSource UncheckedImage
{
get { return (ImageSource)base.GetValue(FalseStateImageProperty); }
set { base.SetValue(FalseStateImageProperty, value); }
}
// Using a DependencyProperty as the backing store for FalseStateImage. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FalseStateImageProperty =
DependencyProperty.Register("UncheckedImage", typeof(ImageSource), typeof(ImageToggleButton), null);
}
MainWindow:
<ImageToggleButton Checked="{Binding IsPlaying}" CheckedImage="{DynamicResource PauseIcon}" UncheckedImage="{DynamicResource PlayIcon}">
</ImageToggleButton>
Is it possible to use CheckedImage as a default image so that if I am not providing UncheckedImage, then in both checked and unchecked state will show CheckedImage?
You could register a PropertyChangedCallback for the CheckedImage property that sets the value of the other one:
public static readonly DependencyProperty TrueStateImageProperty =
DependencyProperty.Register("CheckedImage", typeof(ImageSource), typeof(ImageToggleButton),
new PropertyMetadata(new PropertyChangedCallback(OnPropChanged)));
private static void OnPropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ImageToggleButton tb = (ImageToggleButton)d;
if (tb.UncheckedImage == null)
tb.UncheckedImage = (ImageSource)e.NewValue;
}
By the way, you should following the dependency property naming conventions: https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/custom-dependency-properties

WPF: Parent which would display a specific child depending on input value

As far as I understand, usual Visibility={Binding SomeValue, Converter={…}} still keeps node in visual and logical tree even if it’s invisible. But what if I want to remove it completely and at the same time keep syntax light?
Right now, I’ve made a class called Switch allowing me to do stuff like that:
<Switch Value="{Binding Status}">
<TextBlock Switch.When="{x:Static Status.NotFound}" Text="Not found" />
<Button Switch.When="{x:Static Status.ConnectionError}" Text="Connection error. Try again?" />
<Grid Switch.When="{x:Static Status.Loaded}">…</Grid>
</Switch>
Here is a source code of that Switch thing.
I like how it looks and works, but sometimes some errors occur. For instance, while removing visual child from its previous location, rarely, but System.InvalidOperationException: Cannot modify the logical children for this node at this time because a tree walk is in progress. might happen. Cases like this are solvable, but the whole thing with them makes me think I’m doing something very wrong. What could it be? Maybe the whole idea is just not compatible with WPF at all? Or maybe I’m just missing something (like that thing that I have to override IEnumerator LogicalChildren { get; } to make it work properly)?
I think the answer is probably that you're trying to reparent the child controls the right way. Bad idea! They're just arbitrary content; don't treat them as controls. The actual reparenting in my code is done by hidden ContentPresenter magic in the template. All our control class code does is just sling them around like potatoes.
Here's a working version of the control that shouldn't give you any backtalk. But note that I had trouble comparing boxed enum values to each other. I'm interested in how you solved that problem.
Switch.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
namespace SwitchTestProject
{
[ContentProperty("Items")]
public class Switch : Control
{
public Switch()
{
Items = new List<DependencyObject>();
}
static Switch()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Switch), new FrameworkPropertyMetadata(typeof(Switch)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
OnValueChanged(null);
}
#region Switch.When Attached Property
public static Object GetWhen(DependencyObject obj)
{
return (Object)obj.GetValue(WhenProperty);
}
public static void SetWhen(DependencyObject obj, Object value)
{
obj.SetValue(WhenProperty, value);
}
public static readonly DependencyProperty WhenProperty =
DependencyProperty.RegisterAttached("When", typeof(Object), typeof(Switch),
new PropertyMetadata(null));
#endregion Switch.When Attached Property
#region Content Property
public Object Content
{
get { return (Object)GetValue(ContentProperty); }
protected set { SetValue(ContentPropertyKey, value); }
}
internal static readonly DependencyPropertyKey ContentPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(Content), typeof(Object), typeof(Switch),
new PropertyMetadata(null));
public static readonly DependencyProperty ContentProperty = ContentPropertyKey.DependencyProperty;
#endregion Content Property
#region Value Property
public Object Value
{
get { return (Object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value), typeof(Object), typeof(Switch),
new FrameworkPropertyMetadata(null, Value_PropertyChanged));
protected static void Value_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as Switch).OnValueChanged(e.OldValue);
}
private void OnValueChanged(object oldValue)
{
if (Value is IComparable)
{
// Boxed value types have to be a special case.
// Unless I jumped to an unwarranted conclusion about == not working.
var icompval = Value as IComparable;
foreach (var item in Items)
{
var icompwhen = GetWhen(item) as IComparable;
if (icompwhen != null && icompval.CompareTo(icompwhen) == 0)
{
Content = item;
return;
}
}
}
else
{
Content = Items.FirstOrDefault(item => GetWhen(item) == Value);
}
}
#endregion Value Property
#region Items Property
public List<DependencyObject> Items
{
get { return (List<DependencyObject>)GetValue(ItemsProperty); }
protected set { SetValue(ItemsPropertyKey, value); }
}
internal static readonly DependencyPropertyKey ItemsPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(Items), typeof(List<DependencyObject>), typeof(Switch),
new PropertyMetadata(null));
public static readonly DependencyProperty ItemsProperty = ItemsPropertyKey.DependencyProperty;
#endregion Items Property
}
}
App.xaml or Themes\Generic.xaml
You could do a lot more with styling the parent here.
<Style TargetType="local:Switch">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Switch">
<ContentPresenter
/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Usage:
<local:Switch
Value="{Binding Status}"
>
<TextBlock
local:Switch.When="{x:Static local:Status.NotFound}"
>This is a test</TextBlock>
<TextBlock
local:Switch.When="{x:Static local:Status.ConnectionError}"
>There was an error in the connection</TextBlock>
</local:Switch>
Pure XAML alternative
The bug in your Switch control is probably fixable, but this will work reliably without any nonsense (other than all the verbosity).
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="NotFound">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="Not found" />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="ConnectionError">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Button Content="Connection error. Try again?" />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="Loaded">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Ellipse
Height="32"
Width="32"
Fill="DeepSkyBlue"
/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
We set the content using DataTemplates rather than setting the Content property directly because if we use the latter method, only one instance of each child control will ever exist, so we wouldn't be able to factor the style out as a resource and reuse it.
And because templating is the canonical way to create new controls in XAML.

Update Normal Property in Dependency property/AttachedProperty,

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 ?
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
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.
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..

How to link buttons in child user-control to parent. C# / WPF

i have a WPF application that also uses a custom control i designed.
in this custom control i have some buttons which i would like to give some actions in the parent window.
how can i do that?
thanks!
You need to expose the Buttons' Commands properties as dependency properties.
Say you have a Custom Control (which is DIFFERENT from a UserControl), defined like this:
<Style TargetType="{x:Type custom:MyButtonedCtrl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type custom:MyButtonedCtrl}">
<Border BorderThickness="4"
CornerRadius="2"
BorderBrush="Black">
<StackPanel>
<Button Command="{TemplateBinding CommandForFirstButton}"/>
<Button Command="{TemplateBinding CommandForSecondButton}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then in your code behind, you have to expose the 2 dependency properties: CommandForFirstButton and CommandForSecondButton (of type ICommand):
public class MyButtonedCtrl : ContentControl
{
static MyButtonedCtrl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButtonedCtrl), new FrameworkPropertyMetadata(typeof(MyButtonedCtrl)));
}
#region CommandForFirstButton
public ICommand CommandForFirstButton
{
get { return (ICommand)GetValue(CommandForFirstButtonProperty); }
set { SetValue(CommandForFirstButtonProperty, value); }
}
// Using a DependencyProperty as the backing store for CommandForFirstButton. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandForFirstButtonProperty =
DependencyProperty.Register("CommandForFirstButton", typeof(ICommand), typeof(MyButtonedCtrl), new UIPropertyMetadata(null));
#endregion
#region CommandForSecondButton
public ICommand CommandForSecondButton
{
get { return (ICommand)GetValue(CommandForSecondButtonProperty); }
set { SetValue(CommandForSecondButtonProperty, value); }
}
// Using a DependencyProperty as the backing store for CommandForSecondButton. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandForSecondButtonProperty =
DependencyProperty.Register("CommandForSecondButton", typeof(ICommand), typeof(MyButtonedCtrl), new UIPropertyMetadata(null));
#endregion
}
And whenever you want to use your control:
<custom:MyButtonedCtrl CommandForFirstButton="{Binding MyCommand}"
CommandForSecondButton="{Binding MyOtherCommand}"/>
EDIT : For a UserControl:
Declared like this:
<UserControl x:Class="MyApp.Infrastructure.CustomControls.MyButtonedCtrl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="buttonedCtrl">
<Grid>
<Border BorderThickness="4"
CornerRadius="2"
BorderBrush="Black">
<StackPanel>
<Button Command="{Binding CommandForFirstButton, ElementName=buttonedCtrl}"/>
<Button Command="{Binding CommandForSecondButton, ElementName=buttonedCtrl}"/>
</StackPanel>
</Border>
</Grid>
</UserControl>
The code-behind would be:
/// <summary>
/// Interaction logic for MyButtonedCtrl.xaml
/// </summary>
public partial class MyButtonedCtrl : UserControl
{
public MyButtonedCtrl()
{
InitializeComponent();
}
#region CommandForFirstButton
public ICommand CommandForFirstButton
{
get { return (ICommand)GetValue(CommandForFirstButtonProperty); }
set { SetValue(CommandForFirstButtonProperty, value); }
}
// Using a DependencyProperty as the backing store for CommandForFirstButton. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandForFirstButtonProperty =
DependencyProperty.Register("CommandForFirstButton", typeof(ICommand), typeof(MyButtonedCtrl), new UIPropertyMetadata(null));
#endregion
#region CommandForSecondButton
public ICommand CommandForSecondButton
{
get { return (ICommand)GetValue(CommandForSecondButtonProperty); }
set { SetValue(CommandForSecondButtonProperty, value); }
}
// Using a DependencyProperty as the backing store for CommandForSecondButton. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandForSecondButtonProperty =
DependencyProperty.Register("CommandForSecondButton", typeof(ICommand), typeof(MyButtonedCtrl), new UIPropertyMetadata(null));
#endregion
}
And you use it the same way.
Hope this helps!

Categories