WPF ItemsControl: - Изменяет свойство Items внутри ItemControle после того, как ItemSource свойство ItemsControl изменяется во время выполнения - PullRequest
0 голосов
/ 21 июля 2011

У меня есть следующий сценарий:

Я использовал один ItemsControl.

Что генерирует Button согласно ItemsSource данной ей?

Теперь

когда я бью nextbutton. [Посмотрите mainwindow.xaml ].

Изменения ItemsSource из ItemsControl (pageControl)

и также должны изменяться background из button, содержимое которого равно свойству CurrentPage согласно моему сценарию.

Предположим,

ШАГ 1: В случае нажатия кнопки сначала я изменю ItemsSource из 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 ]

1 голос
/ 21 июля 2011

Нет необходимости в интерфейсе INotifyPropertyChanged для производного объекта от DependencyObject. Вместо этого вы должны использовать DependencyProperty.

Не рекомендуется изменять всю коллекцию ObservableCollection, поэтому создайте ее и не разрушайте: вместо этого очистите.

Это неправильная практика для доступа к элементам, размещенным внутри ItemsControl (в общем, что-нибудь внутри визуального дерева). В обработчике нажатия кнопки просто напишите следующее:

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

Однако вы ДОЛЖНЫ добавить новое свойство с именем «Page» (тип «int») в класс PageNumber.

Чтобы управлять цветом кнопки, я бы использовал конвертер для MultiBinding.

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>

Я не тестировал программу, но она должна работать.

Приветствия

0 голосов
/ 21 июля 2011

Согласно предложению Марио , у меня есть один конвертер, и он работает нормально. Посмотрите на код ниже. который работает нормально в соответствии с моим требованием ...

Спасибо Марио .

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; 
            }
        }
    }
}
...