WPF绑定ObservableCollection <t> T.Property到XAML中的Window ViewModel

时间:2016-05-03 15:03:35

标签: c# wpf xaml mvvm binding

我从MyModernWindow继承了一个类Window,并添加了一个名为MyTitleLinks的属性和依赖项属性。类型为MyLinkCollection : ObservableCollection<MyLink>。在XAML中,我正在尝试定义MyTitleLinks,并将MyLink.Command属性绑定到Window的ViewModel中的属性。

我尝试过多种绑定方式,包括FindAncestor和ElementName,而且我一直都不成功。

如果使用{Binding AboutCommand}{Binding DataContext.AboutCommand, ElementName=mainWindow},我会在输出中收到此错误:

  

无法为目标找到管理FrameworkElement或FrameworkContentElement   元件。 BindingExpression:路径= AboutCommand;的DataItem = NULL;目标   元素是'MylLink'(HashCode = 30245787);目标属性是'命令'   (输入'ICommand')

如果使用{Binding DataContext.AboutCommand, RelativeSource={RelativeSource AncestorType={x:Type local:MyModernWindow}}}

  

找不到引用'RelativeSource的绑定源   FindAncestor,   AncestorType = 'My.Namespace.MyModernWindow',   AncestorLevel = '1'”。 BindingExpression:路径= DataContext.AboutCommand;   的DataItem = NULL; target元素是'MyLink'(HashCode = 35075009);目标   属性是'Command'(类型'ICommand')

MainWindow.xaml

<local:MyModernWindow x:Class="My.MainWindow"
                              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                              xmlns:local="clr-namespace:My.Controls"
                              IsTitleVisible="True"
                              Style="{StaticResource MyModernWindow}"
                              Title="My Window"
                              WindowStartupLocation="CenterScreen">

        <local:MyModernWindow.MyTitleLinks>
            <local:MyLink DisplayName="Support" Source="https://www.google.com/support/" />
            <local:MyLink DisplayName="About" Command="{Binding AboutCommand}" />
        </local:MyModernWindow.MyTitleLinks>
    </local:MyModernWindow>

MainWindow.xaml.cs

public partial class MainWindow : MyModernWindow
{
    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = new MainWindowViewModel();
    }
}

MyLinkCollection类

public class MyLinkCollection : ObservableCollection<MyLink>
{
}

MyLink课程

public class MyLink : DependencyObject
    {
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(MyLink));
        public static readonly DependencyProperty DisplayNameProperty = DependencyProperty.Register(nameof(DisplayName), typeof(string), typeof(MyLink));
        public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(nameof(Source), typeof(Uri), typeof(MyLink));

        public Uri Source
        {
            get { return (Uri)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        public string DisplayName
        {
            get { return (string)GetValue(DisplayNameProperty); }
            set { SetValue(DisplayNameProperty, value); }
        }

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public MyLink()
        {
            SetCurrentValue(VisibilityProperty, Visibility.Visible);
        }
    }

视图模型

public class MainWindowViewModel
{
    public ICommand AboutCommand { get; private set; }

    public MainWindowViewModel()
    {
        this.AboutCommand = new RelayCommand(OpenAboutWindow);
    }

    private void OpenAboutWindow(object o)
    {
        ModernDialog.ShowMessage("About Screen", "About", MessageBoxButton.OK);
    }
}

我错过了什么?

2 个答案:

答案 0 :(得分:1)

this blog post的帮助下,我明白了。由于MyLinkMyLinkCollection不在可视化树中,因此我使用“代理元素”来提供上下文。

我给了我的窗口一个名字,创建了一个FrameworkElement,然后创建了一个隐藏的ContentControl。这就是我所需要的一切。

这是有效的XAML:

<local:MyModernWindow x:Class="My.MainWindow"
                          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                          xmlns:local="clr-namespace:My.Controls"
                          x:Name="Window"
                          IsTitleVisible="True"
                          Style="{StaticResource MyModernWindow}"
                          Title="My Window"
                          WindowStartupLocation="CenterScreen">
    <local:MyModernWindow.Resources>
        <FrameworkElement x:Key="ProxyElement" DataContext="{Binding DataContext, ElementName=Window}" />
    </local:MyModernWindow.Resources>

    <ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"/>

    <local:MyModernWindow.MyTitleLinks>
        <local:MyLink DisplayName="Support" Source="{Binding DataContext.SupportSource, Source={StaticResource ProxyElement}}" />
        <local:MyLink DisplayName="About" Command="{Binding DataContext.AboutCommand, Source={StaticResource ProxyElement}}" />
    </local:MyModernWindow.MyTitleLinks>
</local:MyModernWindow>

答案 1 :(得分:0)

出现此问题的原因是,DataContext没有从集合或MyLink项继承。

要让WPF无需代理元素即可自动为您管理继承,您需要在树的每一步中添加“ Freezable”,如下所示:

public class MyLinkCollection : FreezableCollection<MyLink>
{
}

public class MyLink : Freezable
{
     // class body
}

Xaml Behaviors Wpf(Microsoft发布的项目)使用相同的方法在Xaml定义的集合内传播DataContext,而无需其他代理