如何将ItemsSource绑定到父窗口的ObservableCollection属性?

时间:2015-07-03 09:19:45

标签: c# wpf data-binding

我知道这个问题曾经被问过很久但到目前为止没有一个解决方案适合我。我尝试将ObservableCollection绑定到组合框的ItemsSource但是失败了。

ObservalbeCollection是Window.cs的一部分:

public partial class RecordSoundWindow2 : Window
{
    public ObservableCollection<string> RecordingDevices { get; set; }

    public RecordSoundWindow2()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        RecordingDevices = new ObservableCollection<string>();

        for (int n = 0; n < WaveIn.DeviceCount; n++)
        {
            RecordingDevices.Add(WaveIn.GetCapabilities(n).ProductName);
        }
    }

我当然知道它会更新我的麦克风名称,但组合框从不显示其内容。到目前为止,我已尝试过以下方法:

<ComboBox DockPanel.Dock="Top" Name="cbDevices" ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=RecordingDevices}"/>
<ComboBox DockPanel.Dock="Top" Name="cbDevices" ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=RecordingDevices}"/>
<ComboBox DockPanel.Dock="Top" Name="cbDevices" ItemsSource="{Binding Path=RecordingDevices}"/>

我已经看到RealtiveSourceFindAncestor有效的许多答案,但不适合我。我在这里缺少什么?

2 个答案:

答案 0 :(得分:0)

您需要将您的媒体资源更改为Dependency Property。除非您设置DataContext

,否则您的绑定将无效

在您的情况下,您继承自Window,因此DependencyProperty是正确的方法。

public ObservableCollection<string> RecordingDevices
    {
        get { return (ObservableCollection<string>)GetValue(RecordingDevicesProperty); }
        set { SetValue(RecordingDevicesProperty, value); }
    }

    // Using a DependencyProperty as the backing store for RecordingDevices.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RecordingDevicesProperty =
        DependencyProperty.Register("RecordingDevices", typeof(ObservableCollection<string>), typeof(RecordSoundWindow2), new PropertyMetadata(null));

答案 1 :(得分:0)

Mike Eason的回答有效。

然而,Clemens'INotifyPropertyChanged方法更清晰,我更喜欢它,所以我将其作为答案发布。

这是XAML:

<ComboBox Name="cbDevices" Width="200" 
    SelectionChanged="cbDevices_SelectionChanged"
    ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=RecordingDevices}"/>

以下是我在另一个答案中找到的解决方案背后的代码,其中更好的INotifyPropertyChanged方法,其中属性名称未作为字符串给出,以后可以更好地重命名变量:

public partial class RecordSoundWindow : Window, INotifyPropertyChanged
{
    private IAudioRecorder Recorder;

    public ObservableCollection<string> RecordingDevices { get; set; }

    public RecordSoundWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        InitRecorder();
    }

    private void InitRecorder()
    {
        RecordingDevices = new ObservableCollection<string>();
        Recorder = new AudioRecorder();

        for (int n = 0; n < WaveIn.DeviceCount; n++)
        {
            RecordingDevices.Add(WaveIn.GetCapabilities(n).ProductName);
            OnMyPropertyChanged(() => RecordingDevices);
        }

        //cbDevices.ItemsSource = RecordingDevices;

        if (RecordingDevices.Count > 0)
            cbDevices.SelectedIndex = 0;

        Recorder.SampleAggregator.MaximumCalculated += OnRecorderMaximumCalculated;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    // Raise the event that a property has changed in order to update the visual elements bound to it
    internal void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    //Converts the passed parameter to its name in string
    internal void OnMyPropertyChanged<T>(Expression<Func<T>> memberExpression)
    {
        MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
        OnPropertyChanged(expressionBody.Member.Name);
    }
}