WPF嵌套的Usercontrol绑定

时间:2011-01-19 21:48:01

标签: wpf xaml binding

我正在尝试将一个值从Window绑定到UserControl中的UserControl。但是,出于某种原因,内部UserControl甚至从未试图绑定到我能说的范围。

MainWindow.xaml

<Window x:Class="PdfExample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:PdfExample">
<Grid>
    <my:FileSystemBrowser HorizontalAlignment="Left" x:Name="fileSystemBrowser1" VerticalAlignment="Top" Height="311" Width="417" RootPath="C:\TFS\AE.Web.ezHealthQuoter.Common\1_Dev\Shared\Pdfs" />
</Grid>

FileSystemBrowser.xaml

<UserControl x:Class="PdfExample.FileSystemBrowser"
         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="300" d:DesignWidth="300" xmlns:my="clr-namespace:PdfExample">
<DockPanel>
    <my:FileSystemTree x:Name="fileSystemTree1" RootPath="{Binding Path=RootPath}" Width="150" />
    <ListBox DockPanel.Dock="Right" />
</DockPanel>

FileSystemBrowser.xaml.cs

    public partial class FileSystemBrowser : UserControl
{
    #region Static Members
    static FileSystemBrowser()
    {
        PropertyChangedCallback rootPathChangedCallback = new PropertyChangedCallback(OnRootPathChanged);
        PropertyMetadata metaData = new PropertyMetadata(rootPathChangedCallback);
        RootPathProperty = DependencyProperty.Register("RootPath", typeof(string), typeof(FileSystemBrowser), metaData);
    }

    static DependencyProperty RootPathProperty;

    public static void OnRootPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as FileSystemBrowser).RootPath = e.NewValue as string;
    }
    #endregion

    public string RootPath
    {
        get { return this.ViewModel.RootPath; }
        set { this.ViewModel.RootPath = value; }
    }

    public FileSystemBrowserViewModel ViewModel
    {
        get;
        protected set;
    }

    public FileSystemBrowser()
    {
        InitializeComponent();
        this.ViewModel = new FileSystemBrowserViewModel();
        this.DataContext = this.ViewModel;
    }
}

public class FileSystemBrowserViewModel : INotifyPropertyChanged
{
    private string _rootPath;
    public string RootPath
    {
        get { return _rootPath; }
        set { _rootPath = value; RaisePropertyChanged("RootPath"); }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

FileSystemTree.xaml

<UserControl x:Class="PdfExample.FileSystemTree"
         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="300" d:DesignWidth="300">
<DockPanel>
    <TreeView SelectedValuePath="{Binding Path=SelectedValuePath, Mode=TwoWay}" HorizontalAlignment="Stretch" Name="treeView1" VerticalAlignment="Stretch" ItemsSource="{Binding RootFolder}" HorizontalContentAlignment="Left" VerticalContentAlignment="Top" Margin="0">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Folders}">                    
                <TextBlock Text="{Binding FolderName}" />
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</DockPanel>

FileSystemTree.xaml.cs

    public partial class FileSystemTree : UserControl, INotifyPropertyChanged
{
    #region Static Members

    static DependencyProperty RootPathProperty;

    static FileSystemTree()
    {
        PropertyChangedCallback rootPathChangedCallback = new PropertyChangedCallback(OnRootPathChanged);
        PropertyMetadata metaData = new PropertyMetadata(rootPathChangedCallback);
        RootPathProperty = DependencyProperty.Register("RootPath", typeof(string), typeof(FileSystemTree), metaData);
    }

    public static void OnRootPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as FileSystemTree).RootPath = e.NewValue as string;
    }

    #endregion

    public string RootPath
    {
        get { return this.ViewModel.RootPath; }
        set { this.ViewModel.RootPath = value; }
    }

    public FileSystemTreeViewModel ViewModel
    {
        get;
        protected set;
    }

    public FileSystemTree()
    {            
        InitializeComponent();
        this.ViewModel = new FileSystemTreeViewModel();
        this.DataContext = this.ViewModel;
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

public class FileSystemTreeViewModel : INotifyPropertyChanged
{
    public IFolder[] RootFolder
    {
        get
        {
            if (RootPath != null)
                return new IFolder[] { new FileSystemFolder(RootPath) };

            return null;
        }
    }

    private string _rootPath;
    public string RootPath
    {
        get { return _rootPath; }
        set
        {
            _rootPath = value;
            RaisePropertyChanged("RootPath");
            RaisePropertyChanged("RootFolder");
        }
    }

    private string _selectedValuePath;
    protected string SelectedValuePath
    {
        get { return _selectedValuePath; }
        set { _selectedValuePath = value; }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

我知道这棵树有效,因为如果我把树放在MainWindow.xaml里面,那很好。但由于某种原因,MainWindow.xaml的RootPath值被绑定到FileSystemBrowser并停在那里。它永远不会一直到FileSystemTree。我错过了什么?

1 个答案:

答案 0 :(得分:2)

确定的信息很少,但我认为问题是没有设置的DataContext。尝试相对绑定,这可能会有所帮助。在FileSystemBrowser.xaml中,更改绑定如下:

<my:FileSystemTree x:Name="fileSystemTree1" 
    RootPath="{Binding Path=RootPath,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" 
    Width="150" />     

另一种可能性是将UserControls this-reference设置为DataContext。这也应该有所帮助。