【问题标题】:UserControl Binding with Model - "property not found"UserControl 与模型绑定 - “找不到属性”
【发布时间】:2014-03-16 19:06:03
【问题描述】:

我制作了一个超级简单的用户控件来浏览文件

<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 路径错误:在“对象”“FileBrowserTextBox”(名称=“”)上找不到“InputFile”属性。绑定表达式:路径=输入文件; DataItem='FileBrowserTextBox' (Name='');目标元素是'FileBrowserTextBox'(名称='');目标属性是“文件路径”(类型“字符串”) System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“FileBrowserTextBox”(名称=“”)上找不到“OutputFile”属性。绑定表达式:路径=输出文件; DataItem='FileBrowserTextBox' (Name='');目标元素是'FileBrowserTextBox'(名称='');目标属性是“文件路径”(类型“字符串”)

这基本上意味着UserControl中没有InputFile和OutputFile,但我试图将控件的FilePath属性与我的模型的InputFile和OutputFile绑定,为什么不起作用?

提前致谢。

【问题讨论】:

    标签: c# wpf xaml user-controls


    【解决方案1】:

    当你这样做时

    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    

    FileBrowserTextBox 中,您覆盖继承的DataContext 更改绑定上下文。这意味着它将尝试在FileBrowserTextBox 控件中查找InputFileOutputFile 属性。删除该行并将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 中为LabelFilePath 你做:

    fileBrowserTextBox.txtFilepath.Text = (string)e.NewValue;
    fileBrowserTextBox.lblLabel.Text = (string)e.NewValue;
    

    如果您只想更改 UI,则根本不需要处理属性更改回调。您在 XAML 中使用了应该为您执行此操作的绑定,采用绑定上下文很好,上面的行只会用固定值覆盖这些绑定

    【讨论】:

    • 非常感谢,这解决了错误。我仍然存在模型中的属性 InputFile 和 OutputFile 根本没有修改的问题。可以是 INotifyPropertyChanged 吗?
    • 你不需要fileBrowserTextBox.txtFilepath.Text = (string)e.NewValue;。实际上,如果您只更改 UI,则根本不需要处理这些属性的属性更改。您使用的绑定将为您执行此操作,这将删除绑定并改用固定值。
    【解决方案2】:

    您已在 FileBrowserTextBox 上将 DataContext 设置为自身,这使得所有默认绑定都搜索自身的属性。

    避免为 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>
    

    如果您想要为 UserControl 保留 DataContext,则必须将 Window 中的代码更改为显式指向 Window 的 DataContext,如下所示:

    <cust:FileBrowserTextBox Label="Input File"
                             FilePath="{Binding DataContext.InputFile, 
                                       RelativeSource={RelativeSource FindAncestor, 
                                           AncestorType=Window}}"/>
    

    您还可以在绑定中使用 ElementName 来代替 RelativeSource,方法是将 x:Name 提供给您的窗口并使用 ElementName 进行绑定,就像在 UserControl 的情况下解释的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 2011-07-22
      • 2012-12-31
      相关资源
      最近更新 更多