首页 \ 问答 \ 使用ItemsControl的页面指示符忽略数据模板(Page indicator using ItemsControl ignores data template)

使用ItemsControl的页面指示符忽略数据模板(Page indicator using ItemsControl ignores data template)

我正在尝试使用ItemsControl创建页面指示器。 我们的想法是绑定到TabControl的选项卡并为每个选项卡显示一个圆圈,颜色由触发器确定,该触发器检查选项卡是否被选中:

<ItemsControl ItemsSource="{Binding Path=Items, ElementName=ATabControl}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type TabItem}">
      <Ellipse x:Name="PageIndicator" Width="6" Height="6" Margin="2,0" />

      <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=IsSelected}" Value="False">
          <Setter TargetName="PageIndicator" Property="Fill" Value="White" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=IsSelected}" Value="True">
          <Setter TargetName="PageIndicator" Property="Fill" Value="Blue" />
        </DataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

它编译没有错误,但我得到列出的选项卡的名称,而不是圆圈。 实际上,它完全忽略了ItemTemplate/DataTemplate 。 实际上,如果我删除后者,显示保持不变。


I'm trying to create a page indicator using ItemsControl. The idea is to bind to the tabs of a TabControl and display a circle for each tab, with the color determined by a trigger that checks whether the tab is selected or not:

<ItemsControl ItemsSource="{Binding Path=Items, ElementName=ATabControl}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type TabItem}">
      <Ellipse x:Name="PageIndicator" Width="6" Height="6" Margin="2,0" />

      <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=IsSelected}" Value="False">
          <Setter TargetName="PageIndicator" Property="Fill" Value="White" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=IsSelected}" Value="True">
          <Setter TargetName="PageIndicator" Property="Fill" Value="Blue" />
        </DataTrigger>
      </DataTemplate.Triggers>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

It compiles without error but instead of the circles, I get the names of the tabs listed. Practically, it ignores the ItemTemplate/DataTemplate completely. Actually, if I remove the latter, the display remains the same all right.


原文:https://stackoverflow.com/questions/24520422
更新时间:2020-10-17 13:10

最满意答案

将UI元素绑定在两个不同的容器中时始终存在问题。 因为一个UI元素只能有1个父元素,所以最后一个父元素将具有实际元素,因此将从前父容器中删除相同的元素。

在您提到的问题中,您试图将UI元素TabItems绑定到项控件,该控件有效地从选项卡控件中拉出原始元素并将它们作为项控件的子项放置。

为了解决这个问题,我提出了一个解决方案,将这些UI元素包装在一个类中,并连接所需的属性。

我尝试使用转换器的解决方案

XAML

<StackPanel xmlns:l="clr-namespace:CSharpWPF">
    <StackPanel.Resources>
        <l:TabItemsConverter x:Key="TabItemsConverter" />
    </StackPanel.Resources>
    <TabControl x:Name="ATabControl">
        <TabItem Header="item 1" />
        <TabItem Header="item 2" />
        <TabItem Header="item 3" />
    </TabControl>
    <ItemsControl ItemsSource="{Binding Path=Items, ElementName=ATabControl,Converter={StaticResource TabItemsConverter}}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"
                            HorizontalAlignment="Center" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Ellipse x:Name="PageIndicator"
                         Width="6"
                         Height="6"
                         Margin="2,0"
                         Fill="Gray" />
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding Path=IsSelected}"
                                 Value="False">
                        <Setter TargetName="PageIndicator"
                                Property="Fill"
                                Value="Gray" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=IsSelected}"
                                 Value="True">
                        <Setter TargetName="PageIndicator"
                                Property="Fill"
                                Value="Blue" />
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

转换器类

namespace CSharpWPF
{
    public class TabItemsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            List<TabItemWrapper> result = new List<TabItemWrapper>();

            foreach (TabItem item in (ItemCollection)value)
            {
                result.Add(new TabItemWrapper(item));
            }
            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        class TabItemWrapper : DependencyObject
        {
            public bool IsSelected
            {
                get { return (bool)GetValue(IsSelectedProperty); }
                set { SetValue(IsSelectedProperty, value); }
            }

            // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsSelectedProperty =
                DependencyProperty.Register("IsSelected", typeof(bool), typeof(TabItemWrapper), new PropertyMetadata(false));

            public TabItemWrapper(TabItem source)
            {
                Binding b = new Binding("IsSelected");
                b.Source = this;
                b.Mode = BindingMode.TwoWay;
                source.SetBinding(TabItem.IsSelectedProperty, b);
            }
        }
    }
}

在这个转换器中,我将标签项的IsSelected到包装类的属性,并使用它在视图中绑定

注意:此转换器仅适用于静态选项卡项,如果您打算在运行时添加或删除选项卡项,则可能需要处理CollectionChanged事件以使结果保持同步。

结果

结果


There is always an issue while binding UI elements in two different containers. as one UI element can have only 1 parent so the last parent will have the actual element and hence the same will be removed from the former parent containers.

in the issue you've mentioned you attempted to bind the UI element TabItems to the items control which effectively pulled the original elements from the tab control and placed them as child of the items control.

in order to solve this issue I propose a solution to wrap such UI elements in a class and wire the properties needed.

I attempted a solution using converter

xaml

<StackPanel xmlns:l="clr-namespace:CSharpWPF">
    <StackPanel.Resources>
        <l:TabItemsConverter x:Key="TabItemsConverter" />
    </StackPanel.Resources>
    <TabControl x:Name="ATabControl">
        <TabItem Header="item 1" />
        <TabItem Header="item 2" />
        <TabItem Header="item 3" />
    </TabControl>
    <ItemsControl ItemsSource="{Binding Path=Items, ElementName=ATabControl,Converter={StaticResource TabItemsConverter}}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"
                            HorizontalAlignment="Center" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Ellipse x:Name="PageIndicator"
                         Width="6"
                         Height="6"
                         Margin="2,0"
                         Fill="Gray" />
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding Path=IsSelected}"
                                 Value="False">
                        <Setter TargetName="PageIndicator"
                                Property="Fill"
                                Value="Gray" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=IsSelected}"
                                 Value="True">
                        <Setter TargetName="PageIndicator"
                                Property="Fill"
                                Value="Blue" />
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

converter class

namespace CSharpWPF
{
    public class TabItemsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            List<TabItemWrapper> result = new List<TabItemWrapper>();

            foreach (TabItem item in (ItemCollection)value)
            {
                result.Add(new TabItemWrapper(item));
            }
            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        class TabItemWrapper : DependencyObject
        {
            public bool IsSelected
            {
                get { return (bool)GetValue(IsSelectedProperty); }
                set { SetValue(IsSelectedProperty, value); }
            }

            // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty IsSelectedProperty =
                DependencyProperty.Register("IsSelected", typeof(bool), typeof(TabItemWrapper), new PropertyMetadata(false));

            public TabItemWrapper(TabItem source)
            {
                Binding b = new Binding("IsSelected");
                b.Source = this;
                b.Mode = BindingMode.TwoWay;
                source.SetBinding(TabItem.IsSelectedProperty, b);
            }
        }
    }
}

in this converter I binded the tab item's IsSelected to the property of a wrapper class and used it to bind in the view

Note: this converter work for static tab items only, if you intend to add or remove the tab items during runtime then perhaps you may need to handle CollectionChanged events to keep the result in sync.

result

result

2014-07-02

相关问答

更多

虚拟化一个ItemsControl?(Virtualizing an ItemsControl?)

实际上还有更多的是使ItemsPanelTemplate使用VirtualizingStackPanel 。 ItemsControl的默认ControlTemplate没有ScrollViewer ,这是虚拟化的关键。 添加到ItemsControl的默认控件模板(使用ListBox的控件模板作为模板)给出以下内容: <ItemsControl VirtualizingStackPanel.IsVirtualizing="True" ScrollViewer.CanContent ...

在ItemsControl上滚动(Scrolling on an ItemsControl)

只需将ScrollViewer放在ItemsControl的周围,而不是放在里面。 像这样的东西: <Pivot TabNavigation="Once"> <PivotItem Header="unread"> <ScrollViewer> <ItemsControl ItemsSource="{Binding Categories}"> //Some ItemsControl properties and stuf ...

我的ItemsControl和数据绑定有什么问题?(What am I doing wrong with my ItemsControl & databinding?)

当您使用默认命名空间之外的类型时,您希望绕过类型名称的默认值转换器。 并且您还希望使用GetType()返回的类型名称,而不是C#编译器使用的类型名称。 首先,确保您已声明引用System命名空间的名称空间前缀,例如: xmlns:sys="clr-namespace:System;assembly=mscorlib" 在DataTemplate ,使用Type标记扩展名引用类型: DataType="{x:Type sys:Byte}" 编辑 这是一个最小的工作示例: <Window x:C ...

WPF与ItemsControl和DataTrigger的数据绑定(WPF data binding with ItemsControl and DataTrigger)

我认为你的类Foo应该实现INotifyPropertyChanged并在IsSelected属性发生变化时调用事件ProprtyChanged。 例如: public class Foo : INotifyPropertyChanged { private string _fooName; private bool _isSelected; protected void OnNotifyPropertyChanged(string property) { ...

ItemsControl中的ItemsControl(ItemsControl within ItemsControl)

我试图编写尽可能小的项目来模仿你的代码 - 我想我得到了同样的问题,因为我和我的AlbumItem虚拟机都有TextBlocks。 对我来说,正在使用AlbumItem ItemsControl.ItemTemplate ,但是直接 - 不是通过ItemsControl.Resources 。 经过一些实验,看起来用于AlbumItems的ContentPresenter无法找到VM的默认DataTemplate。 <ItemsControl x:Class="so_wpf_32587588.Al ...

数据模板只在ItemsControl控件中是必需的吗?(Data Template are only necessary in ItemsControl controls?)

DataTemplates不仅仅用于ItemsControls 它们用于告诉WPF如何在Visual Tree中绘制任何对象。 例如,如果您在VisualTree粘贴User类对象,则可以使用DataTemplate告诉WPF如何绘制该User对象 它们最常用于具有ItemsSource或Content属性的控件中,因为这些是将数据对象插入VisualTree的最常用方法。 在您只想将一个数据项插入VisualTree的特定情况下,我建议使用ContentControl <ContentContr ...

带交替ItemTemplate的Silverlight ItemsControl(Silverlight ItemsControl with Alternating ItemTemplate)

扩展ItemsControl并在PrepareContainerForItemOverride覆盖中,您可以应用交替模板。 protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { if (!object.ReferenceEquals(element, item)) { Conten ...

如何数据绑定到ItemsControl(How to databind to a ItemsControl)

该错误消息指示绑定到属性ItemName , Price , Description的控件的DataContext是ProductListModel而不是ProductQtyItem 。 哪个model / viewmodel具有名为Collection属性以及Collection的类型? 我认为问题出在这里,如果它是ProductListModel类型。 更新: 响应您的更新,尝试从ControlTemplate更改资源定义: <ControlTemplate x:Key="ProductIte ...

ItemsControl OverridesDefaultStyle(ItemsControl OverridesDefaultStyle)

如果要为自定义WPF控件提供默认的默认样式,则应定义一个调用DefaultStyleKeyProperty.OverrideMetadata方法的static构造函数: public class HtNavigationMenuCategoryItem : ItemsControl { static HtNavigationMenuCategoryItem() { DefaultStyleKeyProperty.OverrideMetadata(typeof(HtN ...

使用ItemsControl的页面指示符忽略数据模板(Page indicator using ItemsControl ignores data template)

将UI元素绑定在两个不同的容器中时始终存在问题。 因为一个UI元素只能有1个父元素,所以最后一个父元素将具有实际元素,因此将从前父容器中删除相同的元素。 在您提到的问题中,您试图将UI元素TabItems绑定到项控件,该控件有效地从选项卡控件中拉出原始元素并将它们作为项控件的子项放置。 为了解决这个问题,我提出了一个解决方案,将这些UI元素包装在一个类中,并连接所需的属性。 我尝试使用转换器的解决方案 XAML <StackPanel xmlns:l="clr-namespace:CSharpWP ...

相关文章

更多

最新问答

更多
  • Haml + ActionMailer - Rails?(Haml + ActionMailer - Rails?)
  • 将数据从div标签传递到javascript函数[关闭](Pass data from div tags to javascript function [closed])
  • 如何使用imaplib创建电子邮件并将其发送到特定邮箱(How to create an email and send it to specific mailbox with imaplib)
  • Ruby - 使用`require`命令(Ruby - working with `require` command)
  • 用ng值检索时,在md-input-container中隐藏输入文本字段的值(label hiding input text field value in md-input-container when retrieving with ng-value)
  • 以编程方式将字符串宽度值插入sprintf()(Programmatically insert string width value into sprintf())
  • Matplotlib计算给定字符串的轴坐标范围(Matplotlib Calculate Axis Coordinate Extents Given String)
  • 在同一个流连接上返回多个结果以实现HTML5 Server Sent Events(Returning multiple results on the same stream connection to implement HTML5 Server Sent Events)
  • 限制对特定URL的访问(Apache Tomcat)(Restrict access to specific URL (Apache Tomcat))
  • R中的时间序列与ggplot2(Time Series in R with ggplot2)
  • 自动URL参数编码失败(Automatic URL Parameter Encoding Failing)
  • 是否有任何关于JRuby + Clojure集成的开源示例?(Are there any good open source examples of JRuby + Clojure integration?)
  • ActiveX被认为是旧的/过时的标准吗?(Is ActiveX considered old/outdated by todays standards?)
  • SQL Server中的XML查询(XML Query within SQL Server)
  • PL / SQL:在更新尝试时,删除导致unique_violation异常的行(PL/SQL: on update attempt, delete row which causes unique_violation exception)
  • webpack css-loader localIdent名称哈希长度(webpack css-loader localIdent name hash length)
  • 基诺数解析器(Keno number parser)
  • R:索引数据框列的名称范围(R: Index data frame columns by ranges of their names)
  • 限制ASP .net和Javascript中的多个事件(Restrict multiple events in ASP .net & Javascript)
  • 更改行时SQL查询不更新表(SQL query not updating table when row is changed)
  • JavaScript,document.getElementById不从窗体中抓取?(JavaScript, document.getElementById not grabbing from form?)
  • h2数据库上的Mybatis无法插入数据(Mybatis on h2 database can't insert data)
  • KeyboardWillHideNotification未在iOS 9中触发(KeyboardWillHideNotification not firing in iOS 9)
  • jQuery UI Droppable - 如何实际更改HTML?(jQuery UI Droppable - How to actually change the HTML?)
  • 无法将APK安装到root设备中(Can't install APK into rooted device)
  • 在滚动浏览器时,使jQuery UI对话框不改变它的位置(相对于浏览器)(make jQuery UI dialog not change it's position (relative to the browser) when scrolling browser)
  • 我们可以在NativeScript中使用nedb吗?(Can we use nedb with NativeScript?)
  • 使用CancellationToken的竞争条件,其中CancellationTokenSource仅在主线程上被取消(Race condition with CancellationToken where CancellationTokenSource is only cancelled on the main thread)
  • 使用Framework7从JS更新HTML视图中的数据(Update data in HTML view from JS using Framework7)
  • sql server:选择一个外键为NULL的字段(sql server: select a NULL field that is foreign key)