WPF ItemsControl: - 在运行时更改ItemsControl的ItemSsource属性后更改ItemsControl中的项的属性

时间:2011-07-21 09:59:59

标签: c# .net wpf xaml styles

我有以下情景:

我使用了一个ItemsControl

根据Button生成ItemsSource哪个?

立即,

当我点击nextbutton。[看看 mainwindow.xaml ]。

ItemsSource(页面控件)的ItemsControl更改

根据我的情况,

还必须chagne background button的{​​{1}}内容等于CurrentPage属性。

假设,

第1步:在按钮的点击事件中,我将更改ItemsSource的{​​/ strong> ItemsControl

第2步:然后我将更改 Background 特定按钮。 但是我没有在后台更改,而是出现了错误。

This operation is valid only on elements that have this template applied.

注意: - 如果我在Background内没有任何更改直接更改ItemsSource,我就没有任何问题。

查看以下代码。

Mainwindow.xaml

  <Window x:Class="CurrentPageProblem.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">
    <Window.Resources>
        <Style TargetType="Button" x:Key="buttonStyle">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border  CornerRadius="2,2,2,2"  HorizontalAlignment="Center" x:Name="borderTemplate" Background="{TemplateBinding Background}">
                            <ContentPresenter/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter TargetName="borderTemplate"  Property="Border.BorderBrush" Value="Gray" />
                                <Setter TargetName="borderTemplate"  Property="Border.BorderThickness" Value="1" />
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter TargetName="borderTemplate"  Property="Border.BorderBrush" Value="Lime" />
                            </Trigger>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter TargetName="borderTemplate"  Property="Border.Background" Value="#FD7" />
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter TargetName="borderTemplate"  Property="Border.Background" Value="LightGray"></Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="47*" />
            <RowDefinition Height="264*" />
        </Grid.RowDefinitions>
        <ItemsControl Name="pageControl" ItemsSource="{Binding Path=PageCollection}" Grid.Row="0">
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <Border >
                        <StackPanel>
                            <ItemsPresenter></ItemsPresenter>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemsPanel x:Uid="pageItemTemplate">
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button x:Name="pageNumberButton" Margin="3,4" Style="{StaticResource buttonStyle}" Content="{Binding Path=Page_Number}"></Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

        <Button Content="Next" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="136,98,0,0" Name="nextButton" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    </Grid>
</Window>

Mainwindow.xaml.cs

  public partial class MainWindow : Window,INotifyPropertyChanged
        {
            ObservableCollection<PageNumber> pageCollection = new ObservableCollection<PageNumber>();
            public MainWindow()
            {
                InitializeComponent();

                pageCollection.Add(new PageNumber("  0  "));
                pageCollection.Add(new PageNumber("  1  "));
                pageCollection.Add(new PageNumber("  2  "));
                pageCollection.Add(new PageNumber("  3  "));
                pageCollection.Add(new PageNumber("  4  "));
                pageCollection.Add(new PageNumber("  5  "));

                this.DataContext = this;
            }

            public ObservableCollection<PageNumber> PageCollection
            {
                get { return this.pageCollection; }
                set 
                { 
                    this.pageCollection = value;
                    this.OnPropertyChanged("PageCollection");
                }
            }

            private int currentPage;
            public int CurrentPage
            {
                get { return currentPage; }
                set 
                { 
                    currentPage = value;
                    this.OnPropertyChanged("CurrentPage");
                }
            }

            private void button1_Click(object sender, RoutedEventArgs e)
            {
   #region --  IF I COMMENT THIS MUCH CODE THEN THERE IS NO PROBLEM,,,PROBLEM OCCURES WHEN I UNCOMMENT THE CODE,,, --
            pageCollection.Clear();

            pageCollection.Add(new PageNumber("  0  "));
            pageCollection.Add(new PageNumber("  1  "));
            pageCollection.Add(new PageNumber("  2  "));
            #endregion


                for (int i = 0; i < pageControl.Items.Count; i++)
                {
                    var container = pageControl.ItemContainerGenerator.ContainerFromIndex(i) as ContentPresenter;
                    var button = container.ContentTemplate.FindName("pageNumberButton", container) as Button;

                    if (button.Content.Equals(string.Format("  {0}  ", currentPage)))
                    {
                        button.Background = Brushes.NavajoWhite;
                    }
                    else
                    {
                        button.Background = nextButton.Background;
                    }
                }
                currentPage++;
            }



            #region --  INotifyPropertyChanged Members  --

            public event PropertyChangedEventHandler PropertyChanged;

            public void OnPropertyChanged(string propertyNameArg)
            {
                PropertyChangedEventHandler handler = this.PropertyChanged;
                if (handler != null)
                {
                    handler(this,new PropertyChangedEventArgs(propertyNameArg));
                }
            }
            #endregion
        }

        public class PageNumber 
        {
            private string page_Number;
            public PageNumber(string pageNumberArg)
            {
                this.page_Number = pageNumberArg;
            }
            public string Page_Number
            {
                get { return page_Number; }
                set 
                {
                    page_Number = value; 
                }
            }
        } 

2 个答案:

答案 0 :(得分:1)

在DependencyObject的派生对象上不需要INotifyPropertyChanged接口。您应该使用DependencyProperty。

更改整个ObservableCollection不是一个好习惯,所以创建一个并且不要销毁它:清除它。

访问ItemsControl中托管的项目(更常见的是可视化树内的任何内容)是错误的做法。在按钮单击处理程序中,只需编写以下内容:

Button btn = (Button)e.OriginalSource;
PageNumber pn = (PageNumber)btn.DataContext;
this.CurrentPage = pn.Page;

但是,您必须在PageNumber类中添加名为“Page”的新属性(类型“int”)。

要控制按钮颜色,我会使用转换器进行多重绑定。

public class ButtonColorConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        int current = (int)values[0];
        int button = (int)values[1];

        return button == current
            ? Brushes.NavajoWhite
            : Brushes.XXX;  //set the desired color

    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

但是,必须相应地更改XAML:

<ItemsControl.ItemTemplate>
  <DataTemplate>
    <Button x:Name="pageNumberButton" Margin="3,4" Style="{StaticResource buttonStyle}" Content="{Binding Path=Page_Number}">
      <Button.Background>
        <MultiBinding Converter="{StaticResource xxx}">  //specify the converter seen above
          <Binding Path="CurrentPage" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}" />
          <Binding Path="Page" />
        </MultiBinding>
      </Button.Background>
    </Button>
  </DataTemplate>
</ItemsControl.ItemTemplate>

我没有测试该程序,但它应该可以工作。

干杯

答案 1 :(得分:0)

根据 Mario的建议,我使用了一个转换器,它运行正常。 看看下面的代码。根据我的要求工作得很好......

谢谢马里奥

<强> MainWindow.Xaml

<Window x:Class="CurrentPageProblem.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:Local="clr-namespace:CurrentPageProblem">
    <Window.Resources>
        <Local:ButtonColorConverter x:Key="myConverter">

        </Local:ButtonColorConverter>
        <Style TargetType="Button" x:Key="buttonStyle">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border  CornerRadius="2,2,2,2"  HorizontalAlignment="Center" x:Name="borderTemplate" Background="{TemplateBinding Background}">
                            <ContentPresenter/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter TargetName="borderTemplate"  Property="Border.BorderBrush" Value="Gray" />
                                <Setter TargetName="borderTemplate"  Property="Border.BorderThickness" Value="1" />
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter TargetName="borderTemplate"  Property="Border.BorderBrush" Value="Lime" />
                            </Trigger>
                            <Trigger Property="IsFocused" Value="true">
                                <Setter TargetName="borderTemplate"  Property="Border.Background" Value="#FD7" />
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter TargetName="borderTemplate"  Property="Border.Background" Value="LightGray"></Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="47*" />
            <RowDefinition Height="264*" />
        </Grid.RowDefinitions>
        <ItemsControl Name="pageControl" ItemsSource="{Binding Path=PageCollection}" Grid.Row="0">
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <Border >
                        <StackPanel>
                            <ItemsPresenter></ItemsPresenter>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </ItemsControl.Template>
            <ItemsControl.ItemsPanel x:Uid="pageItemTemplate">
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button x:Name="pageNumberButton" Margin="3,4" Style="{StaticResource buttonStyle}" Content="{Binding Path=Page_Number}">
                        <Button.Background>
                            <MultiBinding Converter="{StaticResource myConverter}">
                                <Binding Path="CurrentPage" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}" />
                                <Binding Path="Page_Number" />
                            </MultiBinding>
                        </Button.Background>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

        <Button Content="Next" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="136,98,0,0" Name="nextButton" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    </Grid>
</Window>

<强> MainWindow.Xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;

namespace CurrentPageProblem
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ObservableCollection<PageNumber> pageCollection = new ObservableCollection<PageNumber>();
        public MainWindow()
        {
            InitializeComponent();

            pageCollection.Add(new PageNumber("  0  "));
            pageCollection.Add(new PageNumber("  1  "));
            pageCollection.Add(new PageNumber("  2  "));
            pageCollection.Add(new PageNumber("  3  "));
            pageCollection.Add(new PageNumber("  4  "));
            pageCollection.Add(new PageNumber("  5  "));

            this.DataContext = this;
        }

        public ObservableCollection<PageNumber> PageCollection
        {
            get { return this.pageCollection; }
            set 
            { 
                this.pageCollection = value;

            }
        }

        private int currentPage;
        public int CurrentPage
        {
            get { return currentPage; }
            set 
            { 
                currentPage = value;

            }
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {

            #region -- THIS CODE WORKS FINE NOW --
            pageCollection.Clear();

            pageCollection.Add(new PageNumber("  0  "));
            pageCollection.Add(new PageNumber("  1  "));
            pageCollection.Add(new PageNumber("  2  "));
            pageCollection.Add(new PageNumber("  3  "));
            pageCollection.Add(new PageNumber("  4  "));
            pageCollection.Add(new PageNumber("  5  "));
            pageCollection.Add(new PageNumber("  6  "));
            pageCollection.Add(new PageNumber("  7  "));
            pageCollection.Add(new PageNumber("  8  "));
            pageCollection.Add(new PageNumber("  9  "));
            #endregion

            currentPage++;

        }

    }
    public class ButtonColorConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            string current = string.Format("  {0}  ", values[0]);
            string button = (string)values[1];


            return button == current
                ? Brushes.NavajoWhite
                : Brushes.White;  //set the desired color

        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class PageNumber 
    {
        private string page_Number;
        public PageNumber(string pageNumberArg)
        {
            this.page_Number = pageNumberArg;
        }
        public string Page_Number
        {
            get { return page_Number; }
            set 
            {
                page_Number = value; 
            }
        }
    }
}