Dependecy property ICommand doesn't work in nested control - c#

I have a UserControl with DependecyProperty:
public static readonly DependencyProperty OpenCommandProperty =
DependencyProperty.Register(
"OpenCommand",
typeof(ICommand),
typeof(BaseRouteFlatView),
new UIPropertyMetadata(null));
public ICommand OpenCommand
{
get { return (ICommand)GetValue(OpenCommandProperty); }
set { SetValue(OpenCommandProperty, value); }
}
In Xaml:
<UserControl x:Name="myUserControl">
<StackPanel>
<Button x:Name="first" Command="{Binding OpenCommand, ElementName=myUserControl}"/> <!--Command works-->
<controls:DropDownButtonControl>
<controls:DropDownButtonControl.DropDownContent>
<Button x:Name="second" Command="{Binding OpenCommand, ElementName=myUserControl}"/> <!--Command doesn't work-->
</controls:DropDownButtonControl.DropDownContent>
</controls:DropDownButtonControl>
</StackPanel>
</abstractions:UserControlBase>
What source I have to specify for working command in second button?

Try the following:
public UserControl()
{
InitializeComponent();
NameScope.SetNameScope(second, NameScope.GetNameScope(this));
}

Related

UserControl's PropertyChangedCallback doesn't run

I have got an usercontrol with some dependency property. One of them (ValueProperty) has got a PropertyChangedCallback but it never run.
namespace test
{
public partial class IndicatorLigth : UserControl
{
public IndicatorLigth()
{
InitializeComponent();
DataContext = this;
CurrentBrush = new SolidColorBrush(InactiveColor);
lIndicator.Background = CurrentBrush;
TurnOnValue = true;
Value = true;
}
public static readonly DependencyProperty ActiveColorProperty =
DependencyProperty.Register("ActiveColor", typeof(Color), typeof(IndicatorLigth), new UIPropertyMetadata(Colors.Green));
public Color ActiveColor
{
get { return (Color)GetValue(ActiveColorProperty); }
set { SetValue(ActiveColorProperty, value); }
}
public static readonly DependencyProperty InactiveColorProperty =
DependencyProperty.Register("InactiveColor", typeof(Color), typeof(IndicatorLigth), new UIPropertyMetadata(Colors.Red));
public Color InactiveColor
{
get { return (Color)GetValue(InactiveColorProperty); }
set { SetValue(InactiveColorProperty, value); }
}
private SolidColorBrush _currentBrush;
public SolidColorBrush CurrentBrush
{
get { return _currentBrush; }
set { _currentBrush = value; }
}
public static readonly DependencyProperty TurnOnValueProperty =
DependencyProperty.Register("TurnOnValue", typeof(bool), typeof(IndicatorLigth), new UIPropertyMetadata(true));
public bool TurnOnValue
{
get { return (bool)GetValue(TurnOnValueProperty); }
set { SetValue(TurnOnValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(bool), typeof(IndicatorLigth),
new FrameworkPropertyMetadata(true,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSetColorChanged));
public bool Value
{
get { return (bool)GetValue(ValueProperty); }
set
{
SetValue(ValueProperty, value);
}
}
private void CheckStatus(bool sign)
{
if (sign == TurnOnValue)
CurrentBrush = new SolidColorBrush(ActiveColor);
else CurrentBrush = new SolidColorBrush(InactiveColor);
}
private static void OnSetColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
IndicatorLigth mycontrol = d as IndicatorLigth;
mycontrol.callmyInstanceMethod(e);
}
private void callmyInstanceMethod(DependencyPropertyChangedEventArgs e)
{
CheckStatus((bool)e.NewValue);
lIndicator.Background = CurrentBrush;
}
}
}
And XAML where I use my usercontrol (I use it in another UserControl):
<UserControl
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:local="clr-namespace:test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" >
...
<StackPanel Orientation="Vertical">
<Label Content="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.Sign}"/>
<StackPanel>
<local:IndicatorLigth ActiveColor="Thistle" Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.Sign}"/>
</StackPanel>
</StackPanel>
The Sign parameter belongs to an IsEnabled bindable property of a ComboBox which not in the XAML code. The label content is correct, it changes when I change combobox enabled status, but my UserControl setter of Value, OnSetColorChanged and callmyInstanceMethod don't fire. Could you tell me what wrong in my code? Thank you very much.
Update: So I was wrong. The code mentioned above is correct. The problem will be occures when I push the stackpanel into a devexpress LayoutGroup HeaderTemplate:
<dxlc:LayoutGroup Orientation="Vertical" VerticalAlignment="Top">
<dxlc:LayoutGroup.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Label Content="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.Sign}"/>
<StackPanel>
<local:IndicatorLigth ActiveColor="Thistle" Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.Sign}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</dxlc:LayoutGroup.HeaderTemplate>
</dxlc:LayoutGroup>
Sorry for disturbing you and thank you for advices. I have found the cause of problem. I needn't use <HeaderTemplate><DataTemplate>, I have to use simple <Header> block :)

DependencyProperty for collection of buttons

I want to give the user the opportunity to set a collection of buttons in my CustomControl.
I tried to solve this with ItemsControl like this:
<ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type cc:MyCustomControl}}, Path=Buttons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Command}">
<Image Source="{Binding MyImageSource}"/>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Buttons DependencyProperty:
public static readonly DependencyProperty ButtonsProperty = DependencyProperty.Register(
"Buttons", typeof(IList), typeof(TileGrid), new PropertyMetadata(default(IList)));
public IList Buttons
{
get { return (IList) GetValue(ButtonsProperty); }
set { SetValue(ButtonsProperty, value); }
}
MyButton class:
public class MyButton: Button
{
public ImageSource MyImageSource { get; set; }
}
And how I want to see it in CustomControl implementation:
<cc:MyCustomControl>
<cc:MyCustomControl.Buttons>
<cc:MyButton Command="{Binding SignDocumentsCommand}"
MyImageSource="pack://application:,,,/CommonResources;component/Images/Icons/pen.png"/>
<cc:MyButton Command="{Binding DeleteDocumentsCommand}"
MyImageSource="pack://application:,,,/CommonResources;component/Images/Icons/remove.png"/>
</cc:MyCustomControl.Buttons>
</cc:MyCustomControl>
But it's not working. In live visual tree i see only MyButtons inside ItemsControl. Is this a right approach? Or i need to solve it another way?
The type that you are using for the Button items in the ItemsControl should not be derived from Button. You may use something simple like shown below. It is also not necessary to declare the Buttons property as dependency property. A simple ObservableCollection is sufficient.
public class MyButtonItem : DependencyObject
{
public static DependencyProperty CommandProperty = DependencyProperty.Register(
nameof(Command), typeof(ICommand), typeof(MyButtonItem));
public static DependencyProperty ImageSourceProperty = DependencyProperty.Register(
nameof(ImageSource), typeof(ImageSource), typeof(MyButtonItem));
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
}
public partial class MyCustomControl : UserControl
{
public MyCustomControl()
{
InitializeComponent();
}
public ObservableCollection<MyButtonItem> Buttons { get; }
= new ObservableCollection<MyButtonItem>();
}
The controls XAML would just be what you already have:
<ItemsControl ItemsSource="{Binding Buttons,
RelativeSource={RelativeSource AncestorType=UserControl}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Command}">
<Image Source="{Binding ImageSource}"/>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You would then add MyButtonItem objects to the Buttons collection:
<cc:MyCustomControl>
<cc:MyCustomControl.Buttons>
<cc:MyButtonItem
Command="{Binding SignDocumentsCommand}"
ImageSource="/CommonResources;component/Images/Icons/pen.png"/>
<cc:MyButtonItem
Command="{Binding DeleteDocumentsCommand}"
ImageSource="/CommonResources;component/Images/Icons/remove.png"/>
</cc:MyCustomControl.Buttons>
</cc:MyCustomControl>

How to execute command on parent window by User control button?

I want to make reusable jog user control. I added usercontrol on the main window.
I want to make like this
usercontrol button clicked -> 'UpJogClickCommand' call 'UpJogRelayCommand' -> execute method(UpJogMove)
But my code is Not working.. when i click button, main code do not execute 'UpJogMove'
[JogButtonControl.xaml]
<UserControl>
<Grid>
<Button Command="{Binding UpJogClickCommand}">
</Grid>
</UserControl>
[JogButtonControl.xaml.cs]
public partial class JogButtonControl : UserControl
{
public static readonly DependencyProperty UpJogClickCommandProperty =
DependencyProperty.Register(
"UpJogClickCommand",
typeof(ICommand),
typeof(JogButtonControl));
public ICommand UpJogClickCommand
{
get { return (ICommand)GetValue(UpJogClickCommandProperty); }
set { SetValue(UpJogClickCommandProperty, value); }
}
public JogButtonControl()
{
InitializeComponent();
}
}
[MainWindow.xaml]
<StackPanel x:Name="TempSP" Grid.Column="7">
<JogControl:JogButtonControl UpJogClickCommand="{Binding Path=UpJogRelayCommand}"
</StackPanel>
[MainWindow.xaml.cs]
private RelayCommand<object> _upJogRelayCommand;
public ICommand UpJogRelayCommand
{
get
{
if (_upJogRelayCommand == null)
{
_upJogRelayCommand = new RelayCommand<object>(UpJogMove);
}
return _upJogRelayCommand;
}
}
private void UpJogMove(object notUsed)
{
Debug.Print("UpJogExcuted():");
MoveToUpDirection();
}
You should specify the source object of the Binding in the XAML of your UserControl, e.g. by setting the RelativeSource property:
<UserControl>
<Grid>
<Button Command="{Binding UpJogClickCommand,
RelativeSource={RelativeSource AncestorType=UserControl}}">
</Grid>
</UserControl>

UserControl with DataContext and DependencyProperty

I want to bind a DependencyProperty and DataContext to my UserControl. DataContext is working, but Setting the DependencyProperty has no effect. This is my UserControl:
<MyProperty:MyPropertyControl DataContext="{Binding SelectedPerson}" IsEnabled="True"/>
And this is the CodeBehind of my UserControl:
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.Register(
"IsEnabled",
typeof(Boolean),
typeof(MyProperty:MyPropertyControl),
new FrameworkPropertyMetadata()
{
DefaultValue = false,
BindsTwoWayByDefault = false,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
});
public MyPropertyControl()
{
InitializeComponent();
}
public Boolean IsEnabled
{
get { return (Boolean)GetValue(IsEnabledProperty); }
set
{
SetValue(IsEnabledProperty, value);
NotifyPropertyChanged("IsEnabled");
}
}
I can set the property IsEnabled to true or false, but it has no effect.
User Control Code:
<Button Content="Test" Width="100" Height="30" IsEnabled="{Binding IsEnabled}" />
You'll have to set the source object of the Binding to the UserControl, e.g. like this:
<Button ... IsEnabled="{Binding IsEnabled,
RelativeSource={RelativeSource AncestorType=UserControl}}" />

Dependency property propagation failing

I made a UserControl called ObjectExplorer :
public partial class ObjectExplorer : UserControl
{
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(List<Node>), typeof(ObjectExplorer), new PropertyMetadata(new List<Node>(), ItemsSet));
public List<Node> Items
{
get { return (List<Node>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
}
Inside the XAML of the control it has :
<TreeView Name="treeView" ItemsSource="{Binding Items}" Padding="0,5,0,0" Grid.Row="1">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal" Margin="4,3" ContextMenu="{Binding Converter={StaticResource NodeTypeToContextMenuConverter}}">
<Image Source="{Binding Converter={StaticResource StringToImageConverter}}" />
<TextBlock Text="{Binding Title}" Padding="4,0,0,0" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
So we can see, the TreeView is bound to the Items DP. Now I am using it in my MainWindow.xaml like so :
<fe:ObjectExplorer x:Name="objExplorer" Items="{Binding DatabaseObjects}" />
So this "instance" of the control, its Items is bound to the DP on MainWindow :
public partial class MainWindow : Window
{
public static readonly DependencyProperty DatabaseObjectsProperty = DependencyProperty.Register("DatabaseObjects", typeof(List<Node>), typeof(MainWindow), new PropertyMetadata(new List<Node>(), DatabaseObjectsPropertySet));
public List<Node> DatabaseObjects
{
get { return (List<Node>)GetValue(DatabaseObjectsProperty); }
set { SetValue(DatabaseObjectsProperty, value); }
}
}
Inside a method on MainWindow.cs I am doing :
List<Node> nodes = new List<Node>();
nodes.add(....);
DatabaseObjects = nodes;
What happens :
The DP on MainWindow triggers its set callback fine.
What does not happen :
The DP on ObjectExplorer does not get called, and nothing is displayed in the TreeView. I got it to work by naming the instance of the custom control (objExplorer) in mainwindow, then manually setting its Items whenever the callback for DatabaseObjects triggers...
private static void DatabaseObjectsPropertySet(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MainWindow)d).objExplorer.Items = (List<Node>)e.NewValue;
}
I would like to know... why?
EDIT:
The MainWindow's DataContext is set in XAML DataContext="{Binding RelativeSource={RelativeSource Self}}
I expect :
Code in MainWindow -> MainWindow.DatabaseObjects DP ||breaks|| ---(binding)--> objExplorer.Items ---> UC.Items ---(Internal Binding)--> TreeView.ItemSource

Categories