WPF ItemsControl:

编程入门 行业动态 更新时间:2024-10-28 11:30:20
本文介绍了WPF ItemsControl:-在运行时更改ItemsControl的ItemSource属性后,更改ItemControle中的项目属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我有以下情况: 我用了一个ItemsControl. 哪个会根据ItemsSource 生成Button ? 现在 当我点击nextbutton时. ItemsControl(pageControl)的ItemsSource 更改. [看一下mainwindow.xaml] 并且还必须更改按钮的背景,该按钮的Content等于CurrentPage 属性CurrentPage属性将每次更改(递增为1),每次单击nextButton 假设, 步骤1:首先在按钮的单击事件中,我将更改ItemsControl的ItemsSource. 步骤2:然后,我将更改特定按钮的背景.但是我没有跟随Background的变化,而是跟随Error. This operation is valid only on elements that have this template applied. 注意:- 如果我直接更改Background而没有对ItemsSource进行任何更改,我不会有任何问题. [在 mainwindow.xaml.cs内部查看] 看看下面的代码. Mainwindow.xaml

I have following Scenario: I have used one ItemsControl. Which generates Button as per ItemsSource Given to it? Now, when i am hitting nextbutton. The ItemsSource of ItemsControl(pageControl) Changes.[have a look mainwindow.xaml] and also have to chagne the background of button which has the Content equals to CurrentPage property CurrentPage Property will Change(Increment to One) Each time i click nextButton Suppose, STEP 1: In click event of button first I will change ItemsSource of ItemsControl. STEP 2: Then I will Change Background of particular button. But instead of changes in Background i am getting following Error. This operation is valid only on elements that have this template applied. NOTE:- I don’t have any problem if I directly changes Background without any changes in ItemsSource.[have a look inside mainwindow.xaml.cs] Have a look at Below Code. Mainwindow.xaml

<Window x:Class="CurrentPageProblem.MainWindow" xmlns="schemas.microsoft/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft/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

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

谢谢........

Thanks........

推荐答案

我认为您应该自己在XAML中完成它. 当我们更改CurrentPage时,只需通知它 在xaml中,使用Multiple Trigger和Condition检查按钮内容是否与CurrentPage相同,然后更改背景. 放置多重触发样式 I think you should do it in XAML it self. When we change the CurrentPage simply Notify it and in xaml, use Multiple Trigger and Condition check the button content is same as CurrentPage then change the background. Put the Multiple Trigger Style

WPF需要从Winforms转变思维,我更喜欢.我建议您查找WPF的M-V-VM模式.您需要做的第一件事是单独的View模型,它使代码很多更清晰,并且将关注点更好地分离了.这是ViewModel基类: WPF requires quite a shift of thinking from winforms, I prefer it. I suggest you look up the M-V-VM pattern for WPF. The first thing you need to do is separate yor View model, it makes the code much cleaner and separates concerns much better. Here is the ViewModel base class: public abstract class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = this.PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } }

然后是该项目的视图模型(请注意代码中的注释!):

Then a view model for the item (please note the comments in code!):

public class PageNumber : ViewModel { bool m_selected = false; //Don''t differentiate between a field and its accessor just by the casing. Pre-pend with _ or m_ ! string m_text; public string Text { get { return m_text; } set { if (m_text == value) return; m_text = value; OnPropertyChanged("Text"); } } //This allows the binding to take care of how the item is displayed. public bool Selected { get { return m_selected; } set { if (m_selected == value) return; m_selected = value; OnPropertyChanged("Selected"); } } public PageNumber(string pageNumberArg, bool selected = false) { //Don''t access the field directly, unless needed! Text = pageNumberArg; Selected = selected; } }

现在编写代码来完成Window类中的混合操作:

And now code to doing what was mixed up in the Window''s class:

public class MyViewModel : ViewModel { PageNumber m_currentPage; //fields should not differ from their accessors by only the case use _name or m_name instead ObservableCollection<pagenumber> m_pageCollection = new ObservableCollection<pagenumber>(); public PageNumber CurrentPage { get { return m_currentPage; } set { if (m_currentPage == value) return; //prevent unecessary refreshing: potenitally expensive m_currentPage = value; OnPropertyChanged("CurrentPage"); } } public ObservableCollection<pagenumber> PageCollection { get { return m_pageCollection; } set { if (m_pageCollection == value) return; m_pageCollection = value; OnPropertyChanged("PageCollection"); } } public void Next() { //I got rid of the clear stuff you had etc for clarity. // Note this is far from perect! // 1) It is possible to select more than one item // 2) It would be better to have a single "SelectedPageNumber" // property of type PageNumber in this MyView class than than // what I have here. This is just to demo the principle int currentIndex = PageCollection.IndexOf(PageCollection.First(x => x.Selected)); PageCollection[currentIndex].Selected = false; PageCollection[currentIndex + 1].Selected = true; } public MyViewModel() { PageCollection.Add(new PageNumber(" 0 ", true)); 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 ")); CurrentPage = PageCollection[0]; } }</pagenumber></pagenumber></pagenumber>

现在,您的窗口代码变得简单了:

Now your window code becomes something simple:

public partial class MainWindow : Window { public MyViewModel ViewModel { get { return DataContext as MyViewModel; } set { DataContext = value; } } public MainWindow() { InitializeComponent(); ViewModel = new MyViewModel(); } private void button1_Click(object sender, RoutedEventArgs e) { ViewModel.Next(); } }

最后,您的Items控件XAML(请注意粗体部分) < itemscontrol name ="pageControl" itemssource ="{Binding Path = PageCollection}" grid.row ="0">

Finally, your Items control XAML (Note the bold part) <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" xmlns:x="#unknown"> <itemspaneltemplate> <stackpanel orientation="Horizontal" /> </itemspaneltemplate> </itemscontrol.itemspanel> <itemscontrol.itemtemplate> <datatemplate> <button x:name="pageNumberButton" margin="3,4" content="{Binding Path=Text}" xmlns:x="#unknown"> <button.style> <style targettype="{x:Type Button}"> <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.triggers> <datatrigger binding="{Binding Path=Selected}" value="true"> <setter property="Background" value="White" /> </datatrigger> </style.triggers> </style> </button.style> </button> </datatemplate> </itemscontrol.itemtemplate>

这使用绑定到PageNumber视图模型的Selected属性的数据触发器,您也可以使用转换器来完成类似的工作.此外,如果要重复使用,可以将样式移到资源上. 请注意,视图模型中几乎没有直接的UI内容,并且绑定可以处理显示端的几乎所有内容,如果您正确使用WPF应用程序,通常就是这种情况.我写了一个完整的银行应用程序,在主窗口的类中几乎没有任何代码,几乎所有内容都由模板和M-V-VM模式处理.

This uses a data trigger bound to the Selected property of the PageNumber view model, you could also use a converter to do a similar job. Additionally you can move the styling out to resources if you want to re-use it. Notice that the there little direct UI stuff in the view model and that binding takes care of pretty much everything on the display side, this is normally the case if you get a WPF app right. I wrote a whole banking app with almost no code in the main window''s class, and nearly everything was handled with templates and the M-V-VM pattern.

更多推荐

WPF ItemsControl:

本文发布于:2023-11-12 03:03:48,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1580324.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:WPF   ItemsControl

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!