WPF の 3 番目の Nested DataBinding が機能しない理由がわかりません。私はEntity FrameworkとSql Server 2012を使用しています。以下は私のエンティティです。アプリケーションは複数のアカウントを持つことができます。Accounts テーブルと Applications テーブルがあります。
エンティティ
1. アプリケーション
2. アカウント
VIEWMODELS
1. ApplicationListViewModel
2. ApplicationViewModel
3. AccountListViewModel
4. AccountViewModel
私のユーザーコントロールでは、次のことをしようとしています:
1. コンボボックスを使用して、ApplicationListViewModel を使用してアプリケーションを選択します (作業中)
2. 選択したアプリケーションで、データグリッド内のすべてのアカウントを表示します (作業中)
3. 選択したアカウントで、特定のアカウントに関する詳細情報を表示します。(選択したアカウントの詳細は表示されません)
<UserControl.Resources>
<vm:ApplicationListViewModel x:Key="AppList" />
</UserControl.Resources>
<StackPanel DataContext="{Binding Source={StaticResource AppList}}">
<Grid>
<Grid.RowDefinitions>
...
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0">
<GroupBox Header="View all">
<StackPanel>
<!-- All Applications List -->
<ComboBox x:Name="cbxApplicationList"
ItemsSource="{Binding Path=ApplicationList}"
DisplayMemberPath="Title" SelectedValuePath="Id"
SelectedItem="{Binding Path=SelectedApplication, Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True" />
<!-- Selected Application Accounts -->
<DataGrid x:Name="dtgAccounts" Height="Auto" Width="auto" AutoGenerateColumns="False"
DataContext="{Binding SelectedApplication.AccountLVM}"
ItemsSource="{Binding Path=AccountList}"
SelectedItem="{Binding SelectedAccount, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Binding="{Binding Path=Title}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</GroupBox>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" >
<GroupBox x:Name="grpBoxAccountDetails" Header="New Account" >
<!-- Selected Account Details -->
<!-- DataContext binding does not appear to work -->
<StackPanel DataContext="{Binding SelectedApplication.AccountLVM.SelectedAccount}" >
<Grid>
<Grid.RowDefinitions>
...
</Grid.ColumnDefinitions>
<TextBlock x:Name="lblApplication" Grid.Row="0" Grid.Column="0" >Application</TextBlock>
<ComboBox x:Name="cbxApplication" Grid.Row="0" Grid.Column="1"
DataContext="{Binding Source={StaticResource AppList}}"
ItemsSource="{Binding ApplicationList}"
DisplayMemberPath="Title" SelectedValuePath="Id"
SelectedValue="{Binding SelectedApplication.AccountLVM.SelectedAccount.ApplicationId}">
</ComboBox>
<TextBlock x:Name="lblTitle" Grid.Row="0" Grid.Column="0" >Title</TextBlock>
<TextBox x:Name="txtTitle" Grid.Row="0" Grid.Column="1" Height="30" Width="200"
Text="{Binding Title}" DataContext="{Binding Mode=OneWay}"></TextBox>
<Button Grid.Row="1" Grid.Column="0" Command="{Binding AddAccount}">Add</Button>
</Grid>
</StackPanel>
</GroupBox>
</StackPanel>
</Grid>
</StackPanel>
ApplicationListViewModel
class ApplicationListViewModel : ViewModelBase
{
myEntities context = new myEntities();
private static ApplicationListViewModel instance = null;
private ObservableCollection<ApplicationViewModel> _ApplicationList = null;
public ObservableCollection<ApplicationViewModel> ApplicationList
{
get
{
return GetApplications();
}
set {
_ApplicationList = value;
OnPropertyChanged("ApplicationList");
}
}
//public ObservableCollection<ApplicationViewModel> Cu
private ApplicationViewModel selectedApplication = null;
public ApplicationViewModel SelectedApplication
{
get
{
return selectedApplication;
}
set
{
selectedApplication = value;
OnPropertyChanged("SelectedApplication");
}
}
//private ICommand showAddCommand;
public ApplicationListViewModel()
{
this._ApplicationList = GetApplications();
}
internal ObservableCollection<ApplicationViewModel> GetApplications()
{
if (_ApplicationList == null)
_ApplicationList = new ObservableCollection<ApplicationViewModel>();
_ApplicationList.Clear();
foreach (Application item in context.Applications)
{
ApplicationViewModel a = new ApplicationViewModel(item);
_ApplicationList.Add(a);
}
return _ApplicationList;
}
public static ApplicationListViewModel Instance()
{
if (instance == null)
instance = new ApplicationListViewModel();
return instance;
}
}
ApplicationViewModel
class ApplicationViewModel : ViewModelBase
{
private myEntities context = new myEntities();
private ApplicationViewModel originalValue;
public ApplicationViewModel()
{
}
public ApplicationViewModel(Application acc)
{
//Initialize property values
this.originalValue = (ApplicationViewModel)this.MemberwiseClone();
}
public ApplicationListViewModel Container
{
get { return ApplicationListViewModel.Instance(); }
}
private AccountListViewModel _AccountLVM = null;
public AccountListViewModel AccountLVM
{
get
{
return GetAccounts();
}
set
{
_AccountLVM = value;
OnPropertyChanged("AccountLVM");
}
}
internal AccountListViewModel GetAccounts()
{
_AccountLVM = new AccountListViewModel();
_AccountLVM.AccountList.Clear();
foreach (Account i in context.Accounts.Where(x=> x.ApplicationId == this.Id))
{
AccountViewModel account = new AccountViewModel(i);
account.Application = this;
_AccountLVM.AccountList.Add(account);
}
return _AccountLVM;
}
}
AccountListViewModel
class AccountListViewModel : ViewModelBase
{
myEntities context = new myEntities();
private static AccountListViewModel instance = null;
private ObservableCollection<AccountViewModel> _accountList = null;
public ObservableCollection<AccountViewModel> AccountList
{
get
{
if (_accountList != null)
return _accountList;
else
return GetAccounts();
}
set {
_accountList = value;
OnPropertyChanged("AccountList");
}
}
private AccountViewModel selectedAccount = null;
public AccountViewModel SelectedAccount
{
get
{
return selectedAccount;
}
set
{
selectedAccount = value;
OnPropertyChanged("SelectedAccount");
}
}
public AccountListViewModel()
{
this._accountList = GetAccounts();
}
internal ObservableCollection<AccountViewModel> GetAccounts()
{
if (_accountList == null)
_accountList = new ObservableCollection<AccountViewModel>();
_accountList.Clear();
foreach (Account item in context.Accounts)
{
AccountViewModel a = new AccountViewModel(item);
_accountList.Add(a);
}
return _accountList;
}
public static AccountListViewModel Instance()
{
if (instance == null)
instance = new AccountListViewModel();
return instance;
}
}
アカウントビューモデル。簡単にするために、ビューモデルの他のすべての初期化ロジックを排除しています。
class AccountViewModel : ViewModelBase
{
private myEntites context = new myEntities();
private AccountViewModel originalValue;
public AccountViewModel()
{
}
public AccountViewModel(Account acc)
{
//Assign property values.
this.originalValue = (AccountViewModel)this.MemberwiseClone();
}
public AccountListViewModel Container
{
get { return AccountListViewModel.Instance(); }
}
public ApplicationViewModel Application
{
get;
set;
}
}
Edit1:
SelectedAccount の詳細をテキスト ボックスで表示するようにデータ バインドすると、テキストが表示されません。
1. ApplicationListViewModel を Combobox にデータバインドできます。
2. SelectedApplication に基づいてビュー AccountList に正常にバインドします
。 3. AccountListViewModel で SelectedAcount にバインドできません。
次の行には、選択したアカウントに関する詳細が表示されていないと思います。すべてのデータバインディング構文を確認しました。プロパティでは、適切な DataContext を表示し、プロパティにバインドできます。しかし、それはテキストを表示しません。DataGrid で個々のレコードを選択すると、呼び出しをデバッグしてオブジェクトを選択できますが、どういうわけかそのオブジェクトが最後のテキスト ボックスに表示されません。
DataContext="{Binding SelectedApplication.AccountLVM.SelectedAccount}"
Edit2:
以下のコメントの提案に基づいて、snoop を試したところ、タイトルのテキスト ボックスの行が赤色で強調表示されているのを確認できました。バインディング パス プロパティとデータ コンテキストを変更しようとしていますが、まだ機能していません。「Delve Binding Expression」をクリックしようとすると、未処理の例外が発生しました。それがスヌープから来たものだとしたら、それが何を意味するのかわかりません。
Edit3:
アカウントの詳細セクションの StackPanel の DataContext プロパティとテキスト ボックスのテキスト プロパティのスクリーンショットを撮りました。
解決策:
以下の提案に基づいて、ソリューションに次の変更を加え、よりシンプルにしました。不必要に複雑にしました。
1. AccountsViewModel
2. AccountViewModel
3. ApplicationViewModel
SelectedApplication
これで、SelectedAccount
すべて 1 つの としてプロパティを作成しましたAccountsViewModel
。複雑な DataContext 構文がすべて削除され、xaml ページに DataContext が 1 つだけになりました。
簡素化されたコード。
class AccountsViewModel: ViewModelBase
{
myEntities context = new myEntities();
private ObservableCollection<ApplicationViewModel> _ApplicationList = null;
public ObservableCollection<ApplicationViewModel> ApplicationList
{
get
{
if (_ApplicationList == null)
{
GetApplications();
}
return _ApplicationList;
}
set
{
_ApplicationList = value;
OnPropertyChanged("ApplicationList");
}
}
internal ObservableCollection<ApplicationViewModel> GetApplications()
{
if (_ApplicationList == null)
_ApplicationList = new ObservableCollection<ApplicationViewModel>();
else
_ApplicationList.Clear();
foreach (Application item in context.Applications)
{
ApplicationViewModel a = new ApplicationViewModel(item);
_ApplicationList.Add(a);
}
return _ApplicationList;
}
//Selected Application Property
private ApplicationViewModel selectedApplication = null;
public ApplicationViewModel SelectedApplication
{
get
{
return selectedApplication;
}
set
{
selectedApplication = value;
this.GetAccounts();
OnPropertyChanged("SelectedApplication");
}
}
private ObservableCollection<AccountViewModel> _accountList = null;
public ObservableCollection<AccountViewModel> AccountList
{
get
{
if (_accountList == null)
GetAccounts();
return _accountList;
}
set
{
_accountList = value;
OnPropertyChanged("AccountList");
}
}
//public ObservableCollection<AccountViewModel> Cu
private AccountViewModel selectedAccount = null;
public AccountViewModel SelectedAccount
{
get
{
return selectedAccount;
}
set
{
selectedAccount = value;
OnPropertyChanged("SelectedAccount");
}
}
internal ObservableCollection<AccountViewModel> GetAccounts()
{
if (_accountList == null)
_accountList = new ObservableCollection<AccountViewModel>();
else
_accountList.Clear();
foreach (Account item in context.Accounts.Where(x => x.ApplicationId == this.SelectedApplication.Id))
{
AccountViewModel a = new AccountViewModel(item);
_accountList.Add(a);
}
return _accountList;
}
}
XAML 側
<UserControl.Resources>
<vm:AccountsViewModel x:Key="ALVModel" />
</UserControl.Resources>
<StackPanel DataContext="{Binding Source={StaticResource ALVModel}}" Margin="0,0,-390,-29">
<StackPanel>
<ComboBox x:Name="cbxApplicationList"
ItemsSource="{Binding Path=ApplicationList}"
DisplayMemberPath="Title" SelectedValuePath="Id"
SelectedItem="{Binding Path=SelectedApplication, Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True"></ComboBox>
<DataGrid x:Name="dtgAccounts" Height="Auto" Width="auto"
AutoGenerateColumns="False"
ItemsSource="{Binding Path=AccountList}"
SelectedItem="{Binding SelectedAccount, Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Binding="{Binding Path=Title}"></DataGridTextColumn>
<DataGridTextColumn Header="CreatedDate" Binding="{Binding Path=CreatedDate}"></DataGridTextColumn>
<DataGridTextColumn Header="LastModified" Binding="{Binding Path=LastModifiedDate}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
<StackPanel Height="Auto" Width="300" HorizontalAlignment="Left" DataContext="{Binding Path=SelectedAccount}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock x:Name="lblTitle" Grid.Row="0" Grid.Column="0" >Title</TextBlock>
<TextBox x:Name="txtTitle" Grid.Row="0" Grid.Column="1" Height="30" Width="200"
Text="{Binding Title}"></TextBox>
</Grid>
</StackPanel>
</StackPanel>
MVVM の概念を正しく理解していませんでした。すべてをモジュール化しようとしましたが、結局失敗しました。