问题与DependencyProperty绑定

我创build了一个小的文件浏览器控制:

<UserControl x:Class="Test.UserControls.FileBrowserControl" 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="44" d:DesignWidth="461" Name="Control"> <Grid Margin="3"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBox Margin="3" Text="{Binding SelectedFile}" IsReadOnly="True" TextWrapping="Wrap" /> <Button HorizontalAlignment="Right" Margin="3" Width="100" Content="Browse" Grid.Column="1" Command="{Binding BrowseCommand}" /> </Grid> </UserControl> 

有了下面的代码:

 public partial class FileBrowserControl : UserControl { public ICommand BrowseCommand { get; set; } //The dependency property public static DependencyProperty SelectedFileProperty = DependencyProperty.Register("SelectedFile", typeof(string),typeof(FileBrowserControl), new PropertyMetadata(String.Empty)); public string SelectedFile { get{ return (string)GetValue(SelectedFileProperty);} set{ SetValue(SelectedFileProperty, value);}} //For my first test, this is a static string public string Filter { get; set; } public FileBrowserControl() { InitializeComponent(); BrowseCommand = new RelayCommand(Browse); Control.DataContext = this; } private void Browse() { SaveFileDialog dialog = new SaveFileDialog(); if (Filter != null) { dialog.Filter = Filter; } if (dialog.ShowDialog() == true) { SelectedFile = dialog.FileName; } } } 

我这样使用它:

 <userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" Filter="XSLT File (*.xsl)|*.xsl|All Files (*.*)|*.*"/> 

(SelectedFile是使用此控件的usercontrol的ViewModel的属性)

目前的问题是,当我点击浏览时,usercontrol中的文本框正确更新,但viewmodel父控件的SelectedFile属性没有设置(没有调用set属性)。

如果我将绑定的模式设置为TwoWay,我得到了这个exception:

 An unhandled exception of type 'System.StackOverflowException' occurred in Unknown Module. 

那么我做错了什么?

主要的问题是你的UserControl的DataContext在其构造函数中设置为自己:

 DataContext = this; 

你不应该那样做,因为它有效地阻止了把你的控件的属性绑定到视图模型。

相反,你可以像这样改变UserControl的XAML中的绑定:

 <TextBox Text="{Binding SelectedFile, RelativeSource={RelativeSource AncestorType=UserControl}}" /> 

现在,当你使用你的UserControl并写入一个绑定

 <userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" /> 

SelectedFile属性被绑定到视图模型中的SelectedFile属性,该属性应该位于从父控件inheritance的DataContext中。

使用这个:

 <userControls:FileBrowserControl SelectedFile="{Binding SelectedFile}" ... 

FileBrowserControl的DataContext已经被设置为自己,所以你实际上要求绑定到DataContext是FileBrowserControl而不是父ViewModel的SelectedFile。

为您的视图命名并使用ElementName绑定。

 SelectedFile="{Binding DataContext.SelectedFile, ElementName=element}" 

不要在usercontrol里面设置UserControl的DataContext:

这是错误的:

 this.DataContext = someDataContext; 

因为如果有人使用你的用户控件,通常的做法是设置它的数据上下文,这与你之前设置的内容有冲突

 <my:SomeUserControls DataContext="{Binding SomeDataContext}" /> 

哪一个会被使用? 那么,这取决于…

Name属性也是如此。 你不应该这样设置UserControl的名字:

 <UserControl x:Class="WpfApplication1.SomeUserControl" Name="MyUserControl1" /> 

因为它是有冲突的

 <my:SomeUserControls Name="SomeOtherName" /> 

解:
在你的控制中,只需使用RelativeSource Mode = FindAncestor:

 <TextBox Text="{Binding SelectedFile, RelativeSource={RelativeSource AncestorType="userControls:FileBrowserControl"}" /> 

关于如何完成所有这些第三方控件的问题:他们使用TemplateBinding。 但TemplateBinding只能在ControlTemplate中使用。 http://www.codeproject.com/Tips/599954/WPF-TemplateBinding-with-ControlTemplate

在用户控件中,xaml表示UserControl的内容,而不是ControlTemplate /