问题
I've created a UserControl
for displaying a Hyperlink in my application.
The markup of this UserControl
looks like:
<UserControl x:Class="MVVMExample.View.UserControls.ActionLink"
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>
<TextBlock Margin="5">
<Hyperlink Command="{Binding LinkCommand}" CommandParameter="{Binding LinkCommandParameter}">
<TextBlock Text="{Binding LinkText, UpdateSourceTrigger=PropertyChanged}"/>
</Hyperlink>
</TextBlock>
</Grid>
</UserControl>
The DataContext
of this UserControl
is in the CodeBehind which looks like:
public partial class ActionLink : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty LinkTextProperty = DependencyProperty.Register(
"LinkText", typeof (string), typeof (ActionLink), new PropertyMetadata(LinkTextChanged));
public static readonly DependencyProperty LinkCommandParameterProperty = DependencyProperty.Register(
"LinkCommandParameter", typeof (object), typeof (ActionLink),
new PropertyMetadata(LinkCommandParameterChanged));
public static readonly DependencyProperty LinkCommandProperty = DependencyProperty.Register(
"LinkCommand", typeof (ICommand), typeof (ActionLink), new PropertyMetadata(LinkCommandChanged));
public ActionLink()
{
InitializeComponent();
}
public object LinkCommandParameter
{
get { return GetValue(LinkCommandParameterProperty); }
set { SetValue(LinkCommandParameterProperty, value); }
}
public string LinkText
{
get { return (string) GetValue(LinkTextProperty); }
set
{
SetValue(LinkTextProperty, value);
OnPropertyChanged();
}
}
public ICommand LinkCommand
{
get { return (ICommand) GetValue(LinkCommandProperty); }
set { SetValue(LinkCommandProperty, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private static void LinkTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ActionLink) d).LinkText = (string) e.NewValue;
}
private static void LinkCommandParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ActionLink) d).LinkCommandParameter = e.NewValue;
}
private static void LinkCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ActionLink) d).LinkCommand = (ICommand) e.NewValue;
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Everything just works fine.
Now if I want to use this UserControl
with the Command-Binding I have to do the following:
<userControls:ActionLink LinkText="View customers" LinkCommand="{Binding DataContext.ViewCustomersCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/>
If I use a Button
instead I don't have to provide that RelativeSource
. Is there a opportunity that I also don't have to provide a RelativeSource
on binding properties of custom created UserControl
s?
回答1:
When you write
<userControls:ActionLink LinkCommand="{Binding ViewCustomersCommand}"/>
WPF tries to establish a data binding to a ViewCustomersCommand
property in the DataContext of your UserControl, which is usually inherited from the control's parent, and holds a reference to some view model object. This doesn't work here because you have explicitly set the DataContext to the UserControl instance.
As soon as you have bindable properties (i.e. dependency properties) in your UserControl, you should not set its DataContext. If you do so, you will always have to specifiy the binding source objects explicitly, because the DataContext is no longer inherited.
So remove the
DataContext="{Binding RelativeSource={RelativeSource Self}}"
setting from your UserControl's XAML and set a RelativeSource in all its internal bindings:
<Hyperlink
Command="{Binding LinkCommand,
RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding LinkCommandParameter,
RelativeSource={RelativeSource AncestorType=UserControl}}">
<TextBlock
Text="{Binding LinkText,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
</Hyperlink>
来源:https://stackoverflow.com/questions/29075720/relativesource-binding-for-usercontrol