WPF Nested Usercontrol bindings

霸气de小男生 提交于 2019-12-22 10:59:07

问题


I'm trying to bind a value down from a Window into a UserControl inside a UserControl. But, for some reason, the inner UserControl never even attempts to bind as far as I can tell.

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
}

I know that the tree works, because if I just put the tree inside MainWindow.xaml, it's fine. But for some reason, the RootPath value from MainWindow.xaml gets bound into FileSystemBrowser and stops there. It never makes it all the way down to FileSystemTree. What am I missing?


回答1:


There is to few information to be certain, but I think the problem is the DataContext that is not set. Try relative bindings, this will probably help. In FileSystemBrowser.xaml change the binding as follows:

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

Another possibility would be to set the UserControls this-reference to the DataContext. This should also help.



来源:https://stackoverflow.com/questions/4741178/wpf-nested-usercontrol-bindings

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!