0

我有一个下载器,它有一个进度属性,即:

    public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register("Progress", typeof(int), typeof(Downloader), new PropertyMetadata(0, new PropertyChangedCallback(OnProgressChange)));

    public int Progress
    {
        get { return (int)this.GetValue(ProgressProperty); }
        private set { this.SetValue(ProgressProperty, value); }
    }

    private static void OnProgressChange(DependencyObject @object, DependencyPropertyChangedEventArgs e)
    {
        Downloader d = @object as Downloader;
        if (d.PropertyChanged != null) d.PropertyChanged(d, new PropertyChangedEventArgs("Progress"));
    }

当我尝试在其他类 xaml 中使用它时(m_downloader 是 Downloader 类型的私有字段):

<sdk:Label Height="24" HorizontalAlignment="Left" Margin="360,12,0,0" Name="ProgressLabel" VerticalAlignment="Top" Width="38" Content="{Binding Path=m_downloader.Progress, StringFormat='\{0\} %'}" />

什么都没发生。在调试期间,我可以看到 d.PropertyChanged 始终为空。如何在标签中显示进度?

编辑1:

m_downloader 像这样工作(临时更改属性后):

public partial class AudioPlayer : UserControl
{
    public AudioPlayer()
    {
        m_downloader = new Downloader();
        InitializeComponent();
    }
    ...
    public Downloader m_downloader {get; private set;}
}

编辑2:

我已经在 Blend 中完成了绑定,它将 xaml 更改为:

<UserControl x:Name="audioPlayer" x:Class="Media.Controls.AudioPlayer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="125" d:DesignWidth="410" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

<Grid x:Name="LayoutRoot" Background="White">
    ...
    <sdk:Label Height="24" HorizontalAlignment="Left" Margin="337,12,0,0" Name="ProgressLabel" VerticalAlignment="Top" Width="61" Content="{Binding m_downloader.Progress, ElementName=audioPlayer, Mode=OneWay}" />
    ...
</Grid>
</UserControl>

为什么 ElementName 设置为嵌套的名称,而不是嵌套的名称?这对我来说没有意义......但在这个改变之后它正在工作。

4

1 回答 1

1

由于您在进行解释,因此绑定机制的工作方式如下:

  1. 绑定机制取决于两件事:Binding 上的 Path 和 Source

  2. 在您的情况下,路径是“m_Downloader.Progress”,如果未明确设置源,则绑定回退到使用标签上的 DataContext

  3. 如果标签上没有设置 DataContext,它会在可视树上搜索 DataContext。

  4. 您可以使用 {Binding Source=...} 或 {Binding ElementName=...} 显式设置源

例如,以下将不起作用:

<sdk:Label 
   x:Name="ProgressLabel"
   Content="{Binding Path=Progress}" />

这是因为没有源,也没有设置 DataContext。

您可以使用以下代码在代码中设置它:

ProgressLabel.DataContext = m_Downloader

或者,您可能希望相对于嵌套对象进行绑定。

<sdk:Label
   Content="{Binding m_Downloader.Progress}" />

但是,这将不起作用

  1. m_Downloader 不公开,并且

  2. m_Downloader 甚至不是属性

  3. 未设置 DataContext。

要解决此问题,请使用以下命令:

公共下载器 下载器 {get; 设置;|

public void InitializeComponent() { // ...

 // set DataContext to nesting object
 ProgressLabel.DataContext = this; 

}

如果不想在代码中设置 DataContext,可以显式设置源。由于 AudioPlayer 有一个元素名称

<UserControl x:Name="AudioPlayer" ... />

您可以在绑定中引用它

<sdk:Label
   Content="{Binding m_Downloader.Progress, ElementName=AudioPlayer}" />

最后,您还可以通过将 AudioPlayer 上的 DataContext 设置为自身来完成此操作。

<UserControl
   DataContext="{Binding RelativeSource={RelativeSource Self}}" />

<sdk:Label
   Content="{Binding m_Downloader.Progress}" />
于 2012-05-03T22:15:19.230 回答