绑定到包含 ItemsControl 数据的 UserControl

Posted

技术标签:

【中文标题】绑定到包含 ItemsControl 数据的 UserControl【英文标题】:Binding to the UserControl which contains the ItemControl data 【发布时间】:2012-09-27 18:37:18 【问题描述】:

我创建了一个 UserControl (MediaList),其中包含一个绑定到属性“ToolsBar”的 ItemControl。这个想法是允许从 MediaList 控件外部添加自定义按钮/控件。

我的问题是我正在尝试在工具栏中添加一个按钮,该按钮与 UserControl 本身具有绑定。我不会将 MediaList (UserControl) 的 DataContext 覆盖为“this”,因为我需要使用在根窗口中定义的 DataModel。

也许我这样做的方式完全错误?

这是一个使用 MediaList 自定义按钮的窗口示例:

<localControls:MediaList x:Name="NewMediaList">
                <localControls:MediaList.ToolsBar>
                    <Button Content="StaticResource ResourceKey=MoveToPlaylist" 
                            IsEnabled="Binding ElementName=NewMediaList, Path=SelectedMedia, Converter=localConverters:ObjectToBool"/>
                </localControls:MediaList.ToolsBar>
            </localControls:MediaList>

直到现在我尝试了多种绑定都没有成功,例如:

Binding ElementName=MediaListControl, Path=SelectedMedia, Converter=localConverters:ObjectToBool” Binding RelativeSource=x:Static RelativeSource.Self, Path=SelectedMedia, Converter=localConverters:Debug 绑定 SelectedMedia,RelativeSource=RelativeSource FindAncestor,AncestorType=x:Type UserControl 绑定 SelectedMedia,RelativeSource=RelativeSource FindAncestor,AncestorType=x:Type localControls:MediaList

请注意,我将它们从记忆中写回,并且我还尝试将 MediaList.xaml 中的 ItemControl 和 StackPanel(包含 ItemControm)的 DataContext 设置为 MediaList 对象本身。

MediaList.xaml:

<UserControl x:Class="MediaPlaylist.Controls.MediaList"
         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" 
         xmlns:localConverters="clr-namespace:Suisse.MediaPlaylist.Converters"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         x:Name="MediaListControl">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <DataGrid Grid.Row="0" 
              AutoGenerateColumns="False"
              ItemsSource="Binding ElementName=MediaListControl, Path=Playlist.Medias"
              SelectedItem="Binding ElementName=MediaListControl, Path=SelectedMedia, Mode=TwoWay">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Title" 
                                Binding="Binding Title"
                                IsReadOnly="True"/>
            <DataGridTextColumn Header="File" 
                                Binding="Binding FilePath"
                                IsReadOnly="True"/>
        </DataGrid.Columns>
    </DataGrid>

    <StackPanel Orientation="Horizontal"
                HorizontalAlignment="Right"
                Grid.Row="1">
        <ItemsControl ItemsSource="Binding ElementName=MediaListControl, Path=ToolsBar">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
        <Separator Visibility="Binding ElementName=MediaListControl, Path=ToolsBar.Count, Converter=localConverters:ObjectToVisibility" />
        <Button
            HorizontalAlignment="Right"
            Content="Delete"
            Click="OnDelete_Click"
            IsEnabled="Binding ElementName=MediaListControl, Path=SelectedMedia, Converter=localConverters:ObjectToBool"/>
    </StackPanel>
</Grid>

谢谢

【问题讨论】:

您是否尝试过使用完整的命名空间设置祖先类型,例如:x:Type localControls:MediaList? Oups 我在我的问题中犯了一个错误,但是是的,我在你写的时候使用了完整的命名空间 (x:Type localControls:MediaList) 【参考方案1】:

首先,您试图将绑定数据分配给 ItemsControl 的 ItemsSource 属性,这是完全错误的。 取而代之的是,您可以在 MedialList.xaml.cs 中声明 ItemsControl 依赖属性

        public partial class MediaList : UserControl
    
        public MediaList()
        
            InitializeComponent();

        

        public static DependencyProperty ToolsBarProperty = DependencyProperty.
   Register("ToolsBar", typeof(ItemsControl), typeof(MediaList));

        public ItemsControl ToolsBar
        
            get  return (ItemsControl)GetValue(ToolsBarProperty); 
            set  SetValue(ToolsBarProperty, value); 
        
    

然后您可以将 MediaList xaml 更新为

 <StackPanel Orientation="Horizontal"
            HorizontalAlignment="Right"
            Grid.Row="1">
        <ContentControl Content="Binding ElementName=MediaListControl, Path=ToolsBar">

        </ContentControl>

然后您可以将任何集合模板从外部分配给 ToolBar 属性

<localControls:MediaList>
            <localControls:MediaList.ToolsBar>
                <ItemsControl >
                    <ItemsControl.Items>
                        <Button Content="StaticResource ResourceKey=MoveToPlaylist" 
                        IsEnabled="Binding ElementName=NewMediaList, Path=SelectedMedia, Converter=localConverters:ObjectToBool"/>
                        <Label>Hello </Label>
                        <Label> How are you?</Label>
                    </ItemsControl.Items>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </localControls:MediaList.ToolsBar>
        </localControls:MediaList>

希望这能解决您的问题。

注意:我刚刚移出了 MediaList 用户控件中定义的 ItemsControl,并将其替换为 ContentControl。这允许从外部将任何模板设置为 ContentControl 的 Content 属性。

【讨论】:

为什么使用 ItemControl.ItemsSource 是个坏主意?从文档来看,该属性适用于原始数据(例如字符串)和 UIElement。这个想法是给 MediaList 一个控件列表并让它应用一个模板(并为将使用 MediaList 的父级保持简单),无论如何我尝试了你的示例,但绑定仍然不起作用。我通知说,如果创建一个标签(在使用 MediaList 的同一文件中)并绑定到 MediaList 本身之外的 NewMediaList 它正在工作,如果我将标签移动到 ToolsBar 则找不到 NewMediaList。 您能否在运行应用程序时检查输出以查看是否没有抛出任何绑定异常?我怀疑可能存在绑定错误。您是否也将 SelectedMedia 声明为 MediaList.xaml.cs 中的依赖属性? 有一个绑定异常(错误:4:找不到与引用'ElementName = NewMediaList'绑定的源。BindingExpression:Path = SelectedMedia;DataItem = null;目标元素是'Button'(名称= ''); 目标属性是 'IsEnabled' (类型 'Boolean')) 并且 SelectedMedia 是一个有效的属性。 (MediaList 中的按钮绑定到此属性并且运行良好)就像我说的那样,绑定到 ElementName=NewMediaList 的虚拟标签仅在它位于 localControls:MediaList.ToolsBar 标记之外时才起作用... wpf 解析绑定的对象似乎不同于内部/外部 MediaList

以上是关于绑定到包含 ItemsControl 数据的 UserControl的主要内容,如果未能解决你的问题,请参考以下文章

无法将UserControl绑定到ItemsControl [重复]

WPF: WrapPanel 容器的模板数据绑定(ItemsControl)

ItemsControl 中 DataTemplate 中的 WPF UserControl - 如何绑定到 ItemsSource 的父级

背水一战 Windows 10 (50) - 控件(集合类): ItemsControl - 基础知识, 数据绑定, ItemsPresenter, GridViewItemPresenter, Li

在 ItemsControl 中 UpdateSourceTrigger 设置为 PropertyChanged 的​​ ListBox 在键入时失去焦点

wpf异常:某个ItemsControl与它的项源不一致