我制作了一个超级简单的用户控件来浏览文件
<UserControl x:Class="DrumMapConverter.FileBrowserTextBox"
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"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d" Height="24" d:DesignWidth="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Name="lblLabel" Text="{Binding Label, Mode=TwoWay}" MinWidth="150"/>
<Button Grid.Column="1" Content=" ... " Click="BrowseButton_Click"/>
<TextBox Grid.Column="2" Name="txtFilepath" Text="{Binding FilePath, Mode=TwoWay}"/>
</Grid>
</UserControl>
具有2个依赖属性:
标签和文件路径:
// FilePath
public static readonly DependencyProperty FilePathProperty =
DependencyProperty.Register("FilePath", typeof(string), typeof(FileBrowserTextBox), new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(OnFilePathPropertyChanged)));
public string FilePath
{
get { return (string)GetValue(FilePathProperty); }
set { SetValue(FilePathProperty, value); }
}
static void OnFilePathPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var obj = o as FileBrowserTextBox;
if (obj == null)
return;
FileBrowserTextBox fileBrowserTextBox = (FileBrowserTextBox)o;
fileBrowserTextBox.txtFilepath.Text = (string)e.NewValue;
}
// Label
public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register("Label", typeof(string), typeof(FileBrowserTextBox), new UIPropertyMetadata(string.Empty, new PropertyChangedCallback(OnLabelPropertyChanged)));
public string Label
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
static void OnLabelPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var obj = o as FileBrowserTextBox;
if (obj == null)
return;
FileBrowserTextBox fileBrowserTextBox = (FileBrowserTextBox)o;
fileBrowserTextBox.lblLabel.Text = (string)e.NewValue;
}
然后在我的MainWindow ctor中我有这个
private DrumMapConverterDataModel model;
public MainWindow()
{
InitializeComponent();
model = new DrumMapConverterDataModel();
DataContext = model;
}
模型有2个属性:
private string inputFile = "";
public string InputFile
{
get { return inputFile; }
set {
inputFile = value;
OnPropertyChanged("InputFile");
}
}
private string outputFile = "";
public string OutputFile
{
get { return outputFile; }
set
{
outputFile = value;
OnPropertyChanged("OutputFile");
}
}
我在MainWindow.XAML中像这样绑定
<cust:FileBrowserTextBox Label="Input File" FilePath="{Binding InputFile}"/>
<cust:FileBrowserTextBox Label="Output File" FilePath="{Binding OutputFile}"/>
运行它并获得此错误
System.Windows.Data错误:40:BindingExpression路径错误:'object'''FileBrowserTextBox'(Name ='')'上找不到'InputFile'属性。 BindingExpression:路径= INPUTFILE; DataItem ='FileBrowserTextBox'(Name =''); target元素是'FileBrowserTextBox'(Name =''); target属性是'FilePath'(类型'String') System.Windows.Data错误:40:BindingExpression路径错误:'object'''FileBrowserTextBox'(Name ='')'上找不到'OutputFile'属性。 BindingExpression:路径= OUTPUTFILE; DataItem ='FileBrowserTextBox'(Name =''); target元素是'FileBrowserTextBox'(Name =''); target属性是'FilePath'(类型'String')
这基本上意味着UserControl中没有InputFile和OutputFile,但是我试图将控件的FilePath属性与我的模型的InputFile和OutputFile绑定,为什么不起作用?
提前致谢。
答案 0 :(得分:2)
您已在DataContext
上将FileBrowserTextBox
设置为自身,这使得所有默认绑定都会自行搜索属性。
避免为UserControl设置DataContext
并使用ElementName
进行绑定:
<UserControl x:Name="fileBrowserControl">
...
<TextBlock Text="{Binding Label, ElementName=fileBrowserControl}"/>
<Button Grid.Column="1" Content=" ... " Click="BrowseButton_Click"/>
<TextBox Text="{Binding FilePath, ElementName=fileBrowserControl}"/>
...
</UserControl>
或强>
如果想要保留DataContext for UserControl ,则必须更改Window中的代码以明确指向Window的DataContext ,如下所示:
<cust:FileBrowserTextBox Label="Input File"
FilePath="{Binding DataContext.InputFile,
RelativeSource={RelativeSource FindAncestor,
AncestorType=Window}}"/>
代替RelativeSource,您还可以在绑定中使用ElementName,方法是将x:Name
赋予窗口并使用ElementName进行绑定,如UserControl中所述。
答案 1 :(得分:1)
当你这样做时
DataContext="{Binding RelativeSource={RelativeSource Self}}"
在FileBrowserTextBox
中,您覆盖了继承的DataContext
更改绑定上下文。这意味着它会尝试在InputFile
控件中查找OutputFile
和FileBrowserTextBox
属性。删除该行并更改FileBrowserTextBox
中的绑定,以便他们不会影响DataContext
,例如使用RelativeSource
,如下所示:
<TextBlock Grid.Column="0" Name="lblLabel" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=Label}" MinWidth="150"/>
<TextBox Grid.Column="2" Name="txtFilepath" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=FilePath}"/>
也在PropertyChangedCallback
Label
和FilePath
中:
fileBrowserTextBox.txtFilepath.Text = (string)e.NewValue;
fileBrowserTextBox.lblLabel.Text = (string)e.NewValue;
如果您只想更改UI,则根本不需要处理属性更改的回调。您已经在XAML中使用了应该为您执行此操作的绑定,使用绑定上下文很好,上面的行只会用固定值覆盖这些绑定