2011-01-19 10 views
3

私は、UserControl内のUserControlにWindowから値をバインドしようとしています。しかし、何らかの理由で、内部のUserControlは、私が知る限り、バインドしようとしません。WPFネストされたユーザーコントロールバインド

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> 

FileSystemBrows er.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に至ることはありません。私は何が欠けていますか?

答えて

2

特定の情報がありますが、問題は設定されていないDataContextだと思います。相対的なバインディングを試してください。これが役に立ちます。次のようにFileSystemBrowser.xamlで結合を変更:

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

別の可能性は、ユーザーコントロールのDataContextに、この基準を設定することであろう。これも助けになるはずです。

+0

投稿を更新しました。私は各xamlクラスのDataContextをカスタムオブジェクトに設定しています。 FileSystemBreeserで割り当てられたDataContextのプロパティが更新されると、FileSystemTreeの更新がトリガーされるたびに、FileSystemBreeserでバインドされたFileSystemBreeserで宣言されたため、私はその印象を受けました。 – Xaiter

+0

このアップデートを伝播するバインディングはありません。さらに、コンストラクタで 'DataContext'がハード設定されていると、探しているものが得られない可能性があります。 – user7116

+0

コントロールごとにDataContextを割り当てない場合は、すべてデフォルトでWindowレベルで割り当てられたものになります。これは、すべての入れ子になったコントロールが値のために期待していることをWindowに完全に認識させるDataContextオブジェクトを作成する必要があることを意味します。これは、特にネストされたユーザコントロールでの双方向バインディングを混乱させるときに、コントロールの再利用のポイントを打ち負かしているようです。 WPFコントロールを構築する方法についていくつかの根本的な欠点がありますか? – Xaiter

関連する問題