滑动时如何动态添加FlipView项目(文本内容)?
How to dynamic add FlipView item (text content) when swipe?
我想在 UWP 中动态添加新的翻转视图项目。这样我就可以将无限项添加到我的翻转视图中。比如抓取热点新闻,在翻页中一一展示。
从网上找了一些类似的代码,稍微修改了一下。下面是后面的xaml代码和cs代码。如您所见,我想使用 FlipView_SelectionChanged()
动态添加新的翻转视图项目但失败了。我希望添加带有 Name new 3
、Name new 4
...
等文本内容的新翻转视图项目
XAML:
<Grid Name="grid">
<FlipView Name="flipView" ItemsSource="{Binding ModelItems}">
<FlipView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" FontSize="60" />
</StackPanel>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
C#:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
flipView.SelectionChanged += FlipView_SelectionChanged;
}
private void FlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Debug.WriteLine("flipview selection changed...index = " + flipView.SelectedIndex);
BaseViewModel bv = new BaseViewModel();
bv.ModelItems.Add(new BaseViewModelItem() { Name = "Name new " + flipView.SelectedIndex });
//grid.DataContext = bv;
Debug.WriteLine("flipview selection changed...count = " + bv.ModelItems.Count);
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
grid.DataContext = new BaseViewModel();
}
public class BaseViewModelItem
{
public string Name { get; set; }
}
public class BaseViewModel
{
public ObservableCollection<BaseViewModelItem> ModelItems { get; set; }
public BaseViewModel()
{
ModelItems = new ObservableCollection<BaseViewModelItem>();
ModelItems.Add(new BaseViewModelItem() { Name = "Name 1" });
ModelItems.Add(new BaseViewModelItem() { Name = "Name 2" });
ModelItems.Add(new BaseViewModelItem() { Name = "Name 3" });
}
}
}
这里有两件事在起作用。首先,您不需要分配整个视图模型的新实例来进行更改 - 相反,您可以只检索现有视图模型并添加新项目:
var vm = (BaseViewModel)grid.DataContext;
bv.ModelItems.Add(
new BaseViewModelItem() {
Name = "Name new " + flipView.SelectedIndex
});
那么附加事件的时间就有问题了。如果您在构造函数中附加它,它将在第一次设置 DataContext
并且将项目添加到 ObservableCollection
时立即触发 - 并尝试在这一刻添加项目会让你以灾难性的失败告终。相反,您应该仅在设置 DataContext
之后附加事件 - 因此从构造函数中删除 flipView.SelectionChanged += FlipView_SelectionChanged;
到 OnNavigatedTo
after 设置数据上下文:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
grid.DataContext = new BaseViewModel();
flipView.SelectionChanged += FlipView_SelectionChanged;
}
这样的方式将在更改选择时正确添加项目。
我已经修改了您分享的代码。我建议您使用数据绑定而不是 FlipView_SelectionChanged(),只要将项目添加到 ModelItems,它就会更新它所绑定的元素。我希望这会有所帮助。
<Grid Name="grid">
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Add New FlipView Item" Click="Button_Click"/>
<DockPanel Grid.Column="1">
<TextBlock>Flipview Item Count : </TextBlock>
<TextBlock Text="{Binding ModelItems.Count}"/>
</DockPanel>
</Grid>
<FlipView Grid.Row="1" Name="flipView" ItemsSource="{Binding ModelItems,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<FlipView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<DockPanel>
<TextBlock Text="Index:" FontSize="20"/>
<TextBlock Text="{Binding Index}" FontSize="60" />
</DockPanel>
<DockPanel>
<TextBlock Text="Name:" FontSize="20"/>
<TextBlock Text="{Binding Name}" FontSize="60" />
</DockPanel>
</StackPanel>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
逻辑部分代码
//Interaction logic for MainWindow.xaml
public partial class MainWindow : Window
{
public BaseViewModel ViewModel { get; set; } = new BaseViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = ViewModel;
}
static int k = 3;
private void Button_Click(object sender, RoutedEventArgs e) //can also implement using ICommand instead of event
{
this.ViewModel.ModelItems.Add(new BaseModelItem { Index = k, Name = "Name" + ++k });
}
}
//--------Model------------
public class NotifyPropertyChanged : System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public void OnPropertyRaised(string propertyname)
{
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyname));
}
}
public class BaseModelItem : NotifyPropertyChanged
{
string _name = string.Empty;
public string Name
{
get { return _name; }
set { _name = value; OnPropertyRaised("Name"); }
}
int _index = 0;
public int Index
{
get { return _index; }
set { _index = value; OnPropertyRaised("Index"); }
}
}
//--------ViewModel------------
public class BaseViewModel:NotifyPropertyChanged
{
System.Collections.ObjectModel.ObservableCollection<BaseModelItem> _modelItems = new System.Collections.ObjectModel.ObservableCollection<BaseModelItem>();
public System.Collections.ObjectModel.ObservableCollection<BaseModelItem> ModelItems
{
get { return _modelItems; }
set { _modelItems = value; OnPropertyRaised("ModelItems"); }
}
public BaseViewModel()
{
ModelItems = new System.Collections.ObjectModel.ObservableCollection<BaseModelItem>();
ModelItems.Add(new BaseModelItem() { Name = "Name 1", Index = 0 });
ModelItems.Add(new BaseModelItem() { Name = "Name 2", Index = 1 });
ModelItems.Add(new BaseModelItem() { Name = "Name 3", Index = 2 });
}
}
我想在 UWP 中动态添加新的翻转视图项目。这样我就可以将无限项添加到我的翻转视图中。比如抓取热点新闻,在翻页中一一展示。
从网上找了一些类似的代码,稍微修改了一下。下面是后面的xaml代码和cs代码。如您所见,我想使用 FlipView_SelectionChanged()
动态添加新的翻转视图项目但失败了。我希望添加带有 Name new 3
、Name new 4
...
XAML:
<Grid Name="grid">
<FlipView Name="flipView" ItemsSource="{Binding ModelItems}">
<FlipView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" FontSize="60" />
</StackPanel>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
C#:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
flipView.SelectionChanged += FlipView_SelectionChanged;
}
private void FlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Debug.WriteLine("flipview selection changed...index = " + flipView.SelectedIndex);
BaseViewModel bv = new BaseViewModel();
bv.ModelItems.Add(new BaseViewModelItem() { Name = "Name new " + flipView.SelectedIndex });
//grid.DataContext = bv;
Debug.WriteLine("flipview selection changed...count = " + bv.ModelItems.Count);
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
grid.DataContext = new BaseViewModel();
}
public class BaseViewModelItem
{
public string Name { get; set; }
}
public class BaseViewModel
{
public ObservableCollection<BaseViewModelItem> ModelItems { get; set; }
public BaseViewModel()
{
ModelItems = new ObservableCollection<BaseViewModelItem>();
ModelItems.Add(new BaseViewModelItem() { Name = "Name 1" });
ModelItems.Add(new BaseViewModelItem() { Name = "Name 2" });
ModelItems.Add(new BaseViewModelItem() { Name = "Name 3" });
}
}
}
这里有两件事在起作用。首先,您不需要分配整个视图模型的新实例来进行更改 - 相反,您可以只检索现有视图模型并添加新项目:
var vm = (BaseViewModel)grid.DataContext;
bv.ModelItems.Add(
new BaseViewModelItem() {
Name = "Name new " + flipView.SelectedIndex
});
那么附加事件的时间就有问题了。如果您在构造函数中附加它,它将在第一次设置 DataContext
并且将项目添加到 ObservableCollection
时立即触发 - 并尝试在这一刻添加项目会让你以灾难性的失败告终。相反,您应该仅在设置 DataContext
之后附加事件 - 因此从构造函数中删除 flipView.SelectionChanged += FlipView_SelectionChanged;
到 OnNavigatedTo
after 设置数据上下文:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
grid.DataContext = new BaseViewModel();
flipView.SelectionChanged += FlipView_SelectionChanged;
}
这样的方式将在更改选择时正确添加项目。
我已经修改了您分享的代码。我建议您使用数据绑定而不是 FlipView_SelectionChanged(),只要将项目添加到 ModelItems,它就会更新它所绑定的元素。我希望这会有所帮助。
<Grid Name="grid">
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Add New FlipView Item" Click="Button_Click"/>
<DockPanel Grid.Column="1">
<TextBlock>Flipview Item Count : </TextBlock>
<TextBlock Text="{Binding ModelItems.Count}"/>
</DockPanel>
</Grid>
<FlipView Grid.Row="1" Name="flipView" ItemsSource="{Binding ModelItems,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<FlipView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<DockPanel>
<TextBlock Text="Index:" FontSize="20"/>
<TextBlock Text="{Binding Index}" FontSize="60" />
</DockPanel>
<DockPanel>
<TextBlock Text="Name:" FontSize="20"/>
<TextBlock Text="{Binding Name}" FontSize="60" />
</DockPanel>
</StackPanel>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
逻辑部分代码
//Interaction logic for MainWindow.xaml
public partial class MainWindow : Window
{
public BaseViewModel ViewModel { get; set; } = new BaseViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = ViewModel;
}
static int k = 3;
private void Button_Click(object sender, RoutedEventArgs e) //can also implement using ICommand instead of event
{
this.ViewModel.ModelItems.Add(new BaseModelItem { Index = k, Name = "Name" + ++k });
}
}
//--------Model------------
public class NotifyPropertyChanged : System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public void OnPropertyRaised(string propertyname)
{
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyname));
}
}
public class BaseModelItem : NotifyPropertyChanged
{
string _name = string.Empty;
public string Name
{
get { return _name; }
set { _name = value; OnPropertyRaised("Name"); }
}
int _index = 0;
public int Index
{
get { return _index; }
set { _index = value; OnPropertyRaised("Index"); }
}
}
//--------ViewModel------------
public class BaseViewModel:NotifyPropertyChanged
{
System.Collections.ObjectModel.ObservableCollection<BaseModelItem> _modelItems = new System.Collections.ObjectModel.ObservableCollection<BaseModelItem>();
public System.Collections.ObjectModel.ObservableCollection<BaseModelItem> ModelItems
{
get { return _modelItems; }
set { _modelItems = value; OnPropertyRaised("ModelItems"); }
}
public BaseViewModel()
{
ModelItems = new System.Collections.ObjectModel.ObservableCollection<BaseModelItem>();
ModelItems.Add(new BaseModelItem() { Name = "Name 1", Index = 0 });
ModelItems.Add(new BaseModelItem() { Name = "Name 2", Index = 1 });
ModelItems.Add(new BaseModelItem() { Name = "Name 3", Index = 2 });
}
}