私はユニバーサル Windows プラットフォーム (UWP) アプリに取り組んでおり、当惑する (そして少し厄介な問題) に遭遇しました。MainPage から EventDetailPage に移動すると、System.ArgumentException
. これは、データにバインドされたオブジェクトであることを示しています
「値が期待される範囲内にありません」。
値は、MainPageViewModel から EventDetailPageViewModel に渡される ScoutingEvent オブジェクトです。渡されたオブジェクトが null の場合もありますが (理由は不明)、Value にも既定のデータが割り当てられ、EventDetailPage が Bind to value にバインドしようとしたときに null にならないようにします。
私の観点からは、すべてが正しく見えます。私がここに欠けているものはありますか?
MainPage.xaml
<Page x:Class="ScoutsLog.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Behaviors="using:Template10.Behaviors"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:controls="using:Template10.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ScoutsLog.Views"
xmlns:data="using:ScoutsLog.Models"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:ScoutsLog.ViewModels" mc:Ignorable="d">
<Page.DataContext>
<vm:MainPageViewModel />
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<!-- #region default visual states -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveVisualStateGroup">
<VisualState x:Name="VisualStateNarrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NarrowMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO -->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateNormal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NormalMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO -->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource WideMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO -->
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<!-- #endregion -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- page header -->
<controls:PageHeader BackButtonVisibility="Collapsed" Content="Main Page" Frame="{x:Bind Frame}">
<Interactivity:Interaction.Behaviors>
<Behaviors:EllipsisBehavior Visibility="Auto" />
</Interactivity:Interaction.Behaviors>
<controls:PageHeader.SecondaryCommands>
<AppBarButton Click="{x:Bind ViewModel.GotoPrivacy}" Label="Privacy" />
<AppBarButton Click="{x:Bind ViewModel.GotoAbout}" Label="About" />
</controls:PageHeader.SecondaryCommands>
</controls:PageHeader>
<!-- page content -->
<!--<StackPanel Grid.Row="1" VerticalAlignment="Top"
Orientation="Horizontal" Padding="12,8,0,0">
<controls:Resizer>
<TextBox Width="200" MinWidth="200"
MinHeight="60" Margin="0"
Header="Parameter to pass"
Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap">
<Interactivity:Interaction.Behaviors>
<Behaviors:TextBoxEnterKeyBehavior>
<Core:CallMethodAction MethodName="GotoDetailsPage" TargetObject="{Binding}" />
</Behaviors:TextBoxEnterKeyBehavior>
<Core:EventTriggerBehavior>
<Behaviors:FocusAction/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</TextBox>
</controls:Resizer>
<Button Margin="12,0" VerticalAlignment="Bottom"
Click="{x:Bind ViewModel.GotoDetailsPage}" Content="Submit" />
</StackPanel>-->
<ListBox Grid.Row="1" VerticalAlignment="Top" Padding="12,8,0,0" Name="EventsOverviewListBox"
ItemsSource="{x:Bind ViewModel.Events}" SelectionChanged="{x:Bind ViewModel.GotoEventDetailsPage}"
SelectedIndex="{Binding EventsIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="data:ScoutingEvent">
<TextBlock Text="{x:Bind EventName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Page>
MainPageViewModel.cs
using ScoutsLog.Models;
using ScoutsLog.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.Xaml.Navigation;
namespace ScoutsLog.ViewModels
{
public class MainPageViewModel : Mvvm.ViewModelBase
{
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
public List<ScoutingEvent> Events;
public MainPageViewModel()
{
//if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
// Value = "Designtime value";
// Register a handler for BackRequested events and set the
// visibility of the Back button
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
ReadDataFromStorage();
//if (Events == null || Events.Count <= 0)
//{
Events = EventsManager.GetEvents();
//}
}
private async void ReadDataFromStorage()
{
try
{
StorageFile sampleFile = await localFolder.GetFileAsync("dataFile.txt");
String listAsXml = await FileIO.ReadTextAsync(sampleFile);
Events = XmlHandler.DeserializeXmlToList(listAsXml);
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine(e);
}
}
private async void OnBackRequested(object sender, BackRequestedEventArgs e)
{
StorageFile sampleFile = await localFolder.CreateFileAsync("dataFile.txt",
CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(sampleFile, XmlHandler.SerializeListToXml(Events));
}
ScoutingEvent _Value = new ScoutingEvent();
public ScoutingEvent Value { get { return _Value; } set { Set(ref _Value, value); } }
int _EventsIndex = 0;
public int EventsIndex { get { return _EventsIndex; } set { Set(ref _EventsIndex, value); } }
public override void OnNavigatedTo(object parameter, NavigationMode mode, IDictionary<string, object> state)
{
if (state.ContainsKey(nameof(Value)))
Value = (ScoutingEvent)state[nameof(Value)];
state.Clear();
}
public override async Task OnNavigatedFromAsync(IDictionary<string, object> state, bool suspending)
{
if (suspending)
state[nameof(Value)] = Value;
await Task.Yield();
}
public void GotoEventDetailsPage()
{
Value = Events.ElementAt(EventsIndex);
NavigationService.Navigate(typeof(Views.EventDetailPage), Value);
}
public void GotoPrivacy()
{
NavigationService.Navigate(typeof(Views.SettingsPage), 1);
}
public void GotoAbout()
{
NavigationService.Navigate(typeof(Views.SettingsPage), 2);
}
}
}
EventDetailPage.xaml
<Page
x:Class="ScoutsLog.Views.EventDetailPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Behaviors="using:Template10.Behaviors"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:controls="using:Template10.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ScoutsLog.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:ScoutsLog.ViewModels" x:Name="ThisPage"
xmlns:data="using:ScoutsLog.Models"
mc:Ignorable="d">
<Page.DataContext>
<vm:EventDetailsPageViewModel />
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<!-- adaptive states -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveVisualStateGroup">
<VisualState x:Name="VisualStateNarrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NarrowMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO -->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateNormal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NormalMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO -->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource WideMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO -->
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- header -->
<controls:PageHeader Frame="{x:Bind Frame}" Text="Detail Page">
<Interactivity:Interaction.Behaviors>
<Behaviors:EllipsisBehavior Visibility="Auto" />
</Interactivity:Interaction.Behaviors>
</controls:PageHeader>
<GridView Grid.Row="1" VerticalAlignment="Top" Padding="12,8,0,0" Name="EventsOverviewGridView" ItemsSource="{x:Bind ViewModel.Value}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:ScoutingEvent">
<Grid>
<StackPanel Grid.Row="0">
<TextBlock Text="{x:Bind EventName}" />
<ListBox ItemsSource="{x:Bind Companies}">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="data:Company">
<TextBlock Text="{x:Bind CompanyName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
<!-- #endregion -->
</Grid>
</Page>
EventDetailPageViewModel.cs
using ScoutsLog.Models;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.UI.Xaml.Navigation;
namespace ScoutsLog.ViewModels
{
public class EventDetailsPageViewModel : Mvvm.ViewModelBase
{
public EventDetailsPageViewModel()
{
}
ScoutingEvent _Value = new ScoutingEvent { EventName = string.Empty, EventDate = string.Empty, Companies = new List<Company>()};
public ScoutingEvent Value { get { return _Value; } set { Set(ref _Value, value); } }
public override void OnNavigatedTo(object parameter, NavigationMode mode, IDictionary<string, object> state)
{
if (state.ContainsKey(nameof(Value)))
Value = (ScoutingEvent)state[nameof(Value)];
state.Clear();
}
public override async Task OnNavigatedFromAsync(IDictionary<string, object> state, bool suspending)
{
if (suspending)
state[nameof(Value)] = Value;
await Task.Yield();
}
public void GotoDetailsPage()
{
NavigationService.Navigate(typeof(Views.EventDetailPage), Value);
}
public void GotoPrivacy()
{
NavigationService.Navigate(typeof(Views.SettingsPage), 1);
}
public void GotoAbout()
{
NavigationService.Navigate(typeof(Views.SettingsPage), 2);
}
}
}
更新 1: ScoutingEvent.cs の追加
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace ScoutsLog.Models
{
public class ScoutingEvent : INotifyPropertyChanged
{
private string eventName;
public string EventName
{
get
{
return eventName;
}
set
{
if (eventName != value)
{
eventName = value;
OnNotifyPropertyChanged("EventName");
}
}
}
private string eventDate;
public string EventDate
{
get
{
return eventDate;
}
set
{
if (eventDate != value)
{
eventDate = value;
OnNotifyPropertyChanged("EventDate");
}
}
}
public List<Company> Companies { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class Company
{
public string CompanyName { get; set; }
public string Category { get; set; }
public Boolean isRelevent { get; set; }
public String DateVisited { get; set; }
public string Notes { get; set; }
}
public class EventsManager
{
public static List<ScoutingEvent> GetEvents()
{
var events = new List<ScoutingEvent>();
var companies = GetCompanies();
events.Add(new ScoutingEvent { EventName = "CES", EventDate = "1/6/2016 - 1/9/2016", Companies = companies});
events.Add(new ScoutingEvent { EventName = "MWC", EventDate = "3/3/2016 - 3/10/2016", Companies = companies });
return events;
}
public static List<Company> GetCompanies()
{
var companies = new List<Company>();
companies.Add(new Company { CompanyName = "Spire", Category = "Fittness", DateVisited = "1/6/2016", isRelevent = true, Notes = "Follow-up after event." });
companies.Add(new Company { CompanyName = "Samsung", Category = "Fittness", DateVisited = "1/8/2016", isRelevent = false, Notes = "Not working on relevent technologies." });
companies.Add(new Company { CompanyName = "Fitbit", Category = "Fittness", DateVisited = "1/7/2016", isRelevent = true, Notes = "Pass along to remote team." });
companies.Add(new Company { CompanyName = "Home.io", Category = "Fittness", DateVisited = "1/9/2016", isRelevent = true, Notes = "SHare with Paul/Martta." });
return companies;
}
}
}