使用 mvvmcross 和命令在通用应用程序中使用 rss 提要的不同部分
Using different parts of rss feed in a universal app using mvvmcross and commands
所以我一直在尝试使用通用应用程序和 mvvmcross 为 win10 构建一个简单的 rss 提要应用程序,它将执行以下操作:
- 从列表框或类似内容中的地址加载所有项目,这将在拆分视图中显示它们。
- 当点击一个标题时,它会打开一个 WebView,其中包含特定标题的完整文章。
我遇到的问题是将相同 RssItems 的不同部分绑定到不同的控件,但保持它们之间的关系。我对这两种技术都不熟悉,但我认为这应该是可行的,我只是找不到方法。
这些是我写的代码的相关部分:
viewModel.cs:
class FirstViewModel : MvxViewModel
{
private List<string> _rssItems;
public List<string> RssItems
{
get { return _rssItems; }
set { _rssItems = value; RaisePropertyChanged(() => RssItems); }
}
public MvxCommand SelectionChangedCommand
{
get
{
return new MvxCommand(() =>
{
LoadRssItems();
});
}
}
private async void LoadRssItems()
{
List<string> feedItems = new List<string>();
SyndicationClient rssReaderClient = new SyndicationClient();
SyndicationFeed rssFeed = await rssReaderClient.RetrieveFeedAsync(new Uri("xml address"));
if (rssFeed != null)
{
foreach (var item in rssFeed.Items)
{
feedItems.Add(item.Title.Text);
RssItemsOrinigal.Add(item);
}
RssItems = feedItems;
}
}
和firstView.xaml:
<views:MvxWindowsPage
x:Class="RssReader.Views.FirstView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:RssReader.Views"
xmlns:views="using:MvvmCross.WindowsUWP.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<RelativePanel>
<Button x:Name="HamburgerButton"
RelativePanel.AlignLeftWithPanel="True"
FontFamily="Segoe MDL2 Assets"
FontSize="36"
Content=""
Click="HamburgerButton_Click"/>
<SplitView Grid.Row="1"
x:Name="sv"
DisplayMode="CompactOverlay"
OpenPaneLength="200"
CompactPaneLength="50">
<SplitView.Pane>
<ListBox x:Name="lstMenuItems" SelectionMode="Single">
<ListBoxItem x:Name="ListBoxItem1">
<StackPanel Orientation="Horizontal">
<Button FontFamily="Segoe MDL2 Assets" FontSize="36" Command="{Binding SelectionChangedCommand}"></Button>
<TextBlock FontSize="24" Text="Website 1" />
</StackPanel>
</ListBoxItem>
</ListBox>
</SplitView.Pane>
<SplitView.Content>
<ListBox ItemsSource="{Binding RssItems}"/>
</SplitView.Content>
</SplitView>
</Grid>
</views:MvxWindowsPage>
一种方法是将 ContentPresenter 与 ListBox
一起使用,并在每次 select 一个项目或想回到 ListBox
:
<Page.Resources>
<DataTemplate x:Key="DetailContent">
<WebView Source="{Binding DetailUri}" />
</DataTemplate>
<DataTemplate x:Key="ListBoxContent">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</Page.Resources>
...
<SplitView.Content>
<Grid>
<ContentPresenter Content="{x:Bind listBox.SelectedItem, Mode=OneWay}"
ContentTemplate="{StaticResource DetailContent}" Visibility="{x:Bind VM.IsVisible, Mode=OneWay}" />
<ListBox x:Name="listBox" ItemsSource="{x:Bind VM.RssItems}"
ItemTemplate="{StaticResource ListBoxContent}" SelectionChanged="{x:Bind VM.listBox_SelectionChanged}" />
<Button Content="Close and Show ListBox" VerticalAlignment="Bottom" Visibility="{x:Bind VM.IsVisible, Mode=OneWay}"
Click="{x:Bind VM.IsVisible_Clicked}" />
</Grid>
</SplitView.Content>
例如在这个页面的ViewModel中:
public class Page6ViewModel : INotifyPropertyChanged
{
public ObservableCollection<ListBoxDetail> RssItems;
private Visibility _IsVisible = Visibility.Collapsed;
public Visibility IsVisible
{
get { return _IsVisible; }
set
{
if (value != _IsVisible)
{
_IsVisible = value;
OnpropertyChanged();
}
}
}
public Page6ViewModel()
{
RssItems = new ObservableCollection<ListBoxDetail>();
RssItems.Add(new ListBoxDetail { Title = "Item 1", DetailUri = "" });
RssItems.Add(new ListBoxDetail { Title = "Item 2", DetailUri = "https://msdn.microsoft.com/en-us/library/windows/apps/ms668604(v=vs.105).aspx" });
RssItems.Add(new ListBoxDetail { Title = "Item 3", DetailUri = "https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.itemscontrol.itemssource.aspx" });
}
private ListBox listBox;
public void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
listBox = sender as ListBox;
listBox.Visibility = Visibility.Collapsed;
IsVisible = Visibility.Visible;
}
public void IsVisible_Clicked(object sender, RoutedEventArgs e)
{
listBox.Visibility = Visibility.Visible;
IsVisible = Visibility.Collapsed;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnpropertyChanged([CallerMemberName]string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
另一种常见的方法是将Frame用作SpiltView
的Content
,然后首先为ListBox
创建一个页面,为WebView
创建一个页面将此框架导航到 ListBox
的页面,在 SelectionChanged
事件中,您可以将 uri 作为参数发送并将此框架导航到 WebView
的页面。这个方法网上有很多例子,大家可以搜索一下。
所以我一直在尝试使用通用应用程序和 mvvmcross 为 win10 构建一个简单的 rss 提要应用程序,它将执行以下操作:
- 从列表框或类似内容中的地址加载所有项目,这将在拆分视图中显示它们。
- 当点击一个标题时,它会打开一个 WebView,其中包含特定标题的完整文章。
我遇到的问题是将相同 RssItems 的不同部分绑定到不同的控件,但保持它们之间的关系。我对这两种技术都不熟悉,但我认为这应该是可行的,我只是找不到方法。
这些是我写的代码的相关部分:
viewModel.cs:
class FirstViewModel : MvxViewModel
{
private List<string> _rssItems;
public List<string> RssItems
{
get { return _rssItems; }
set { _rssItems = value; RaisePropertyChanged(() => RssItems); }
}
public MvxCommand SelectionChangedCommand
{
get
{
return new MvxCommand(() =>
{
LoadRssItems();
});
}
}
private async void LoadRssItems()
{
List<string> feedItems = new List<string>();
SyndicationClient rssReaderClient = new SyndicationClient();
SyndicationFeed rssFeed = await rssReaderClient.RetrieveFeedAsync(new Uri("xml address"));
if (rssFeed != null)
{
foreach (var item in rssFeed.Items)
{
feedItems.Add(item.Title.Text);
RssItemsOrinigal.Add(item);
}
RssItems = feedItems;
}
}
和firstView.xaml:
<views:MvxWindowsPage
x:Class="RssReader.Views.FirstView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:RssReader.Views"
xmlns:views="using:MvvmCross.WindowsUWP.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<RelativePanel>
<Button x:Name="HamburgerButton"
RelativePanel.AlignLeftWithPanel="True"
FontFamily="Segoe MDL2 Assets"
FontSize="36"
Content=""
Click="HamburgerButton_Click"/>
<SplitView Grid.Row="1"
x:Name="sv"
DisplayMode="CompactOverlay"
OpenPaneLength="200"
CompactPaneLength="50">
<SplitView.Pane>
<ListBox x:Name="lstMenuItems" SelectionMode="Single">
<ListBoxItem x:Name="ListBoxItem1">
<StackPanel Orientation="Horizontal">
<Button FontFamily="Segoe MDL2 Assets" FontSize="36" Command="{Binding SelectionChangedCommand}"></Button>
<TextBlock FontSize="24" Text="Website 1" />
</StackPanel>
</ListBoxItem>
</ListBox>
</SplitView.Pane>
<SplitView.Content>
<ListBox ItemsSource="{Binding RssItems}"/>
</SplitView.Content>
</SplitView>
</Grid>
</views:MvxWindowsPage>
一种方法是将 ContentPresenter 与 ListBox
一起使用,并在每次 select 一个项目或想回到 ListBox
:
<Page.Resources>
<DataTemplate x:Key="DetailContent">
<WebView Source="{Binding DetailUri}" />
</DataTemplate>
<DataTemplate x:Key="ListBoxContent">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</Page.Resources>
...
<SplitView.Content>
<Grid>
<ContentPresenter Content="{x:Bind listBox.SelectedItem, Mode=OneWay}"
ContentTemplate="{StaticResource DetailContent}" Visibility="{x:Bind VM.IsVisible, Mode=OneWay}" />
<ListBox x:Name="listBox" ItemsSource="{x:Bind VM.RssItems}"
ItemTemplate="{StaticResource ListBoxContent}" SelectionChanged="{x:Bind VM.listBox_SelectionChanged}" />
<Button Content="Close and Show ListBox" VerticalAlignment="Bottom" Visibility="{x:Bind VM.IsVisible, Mode=OneWay}"
Click="{x:Bind VM.IsVisible_Clicked}" />
</Grid>
</SplitView.Content>
例如在这个页面的ViewModel中:
public class Page6ViewModel : INotifyPropertyChanged
{
public ObservableCollection<ListBoxDetail> RssItems;
private Visibility _IsVisible = Visibility.Collapsed;
public Visibility IsVisible
{
get { return _IsVisible; }
set
{
if (value != _IsVisible)
{
_IsVisible = value;
OnpropertyChanged();
}
}
}
public Page6ViewModel()
{
RssItems = new ObservableCollection<ListBoxDetail>();
RssItems.Add(new ListBoxDetail { Title = "Item 1", DetailUri = "" });
RssItems.Add(new ListBoxDetail { Title = "Item 2", DetailUri = "https://msdn.microsoft.com/en-us/library/windows/apps/ms668604(v=vs.105).aspx" });
RssItems.Add(new ListBoxDetail { Title = "Item 3", DetailUri = "https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.itemscontrol.itemssource.aspx" });
}
private ListBox listBox;
public void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
listBox = sender as ListBox;
listBox.Visibility = Visibility.Collapsed;
IsVisible = Visibility.Visible;
}
public void IsVisible_Clicked(object sender, RoutedEventArgs e)
{
listBox.Visibility = Visibility.Visible;
IsVisible = Visibility.Collapsed;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnpropertyChanged([CallerMemberName]string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
另一种常见的方法是将Frame用作SpiltView
的Content
,然后首先为ListBox
创建一个页面,为WebView
创建一个页面将此框架导航到 ListBox
的页面,在 SelectionChanged
事件中,您可以将 uri 作为参数发送并将此框架导航到 WebView
的页面。这个方法网上有很多例子,大家可以搜索一下。