ご容赦ください。私は WPF MVVM 開発の初心者です。
私が取り組んでいるユーティリティ (WPF クライアント アプリケーション) には、指定された期間、現在利用可能なデータをユーザーに表示する 4 列のデータグリッドが含まれています。返されるレコードには、レコードを完成させるために最終的に必要なデータのすべてまたは一部が含まれる場合があります。ユーザーは、不足している部分を変更したり、新しい行をまとめて追加したりして、不足しているレコードを埋めることができる必要があります。4 つの列のうち 3 つには、有効な選択肢のみを含むコンボ ボックスが含まれています。最初のコンボがコンボ 2 と 3 の内容を決定するように、コンボ ボックスはカスケードになっています。4 番目の列は単純な価格列です。
デフォルトの戻りデータでグリッドを完全に機能させることができました。コンボボックスは正しく入力され、現在のレコードの値がコンボで選択された項目として表示されます。
私の問題は、新しい行を追加することです。私はこれをインラインで達成しようとしています。つまり、ユーザーがリストの下部にある空白行をクリックするかタブで移動すると、新しい行がコレクションに追加され、入力が受け入れられます。最初のコンボは空の行に入力されますが、値を選択しても変更は他の 2 つのコンボにカスケードされません。ただし、人口の多い行では機能します。
意味がある?私はおそらく誰かがそれを指摘したときに自分自身を蹴るほど愚かで単純なものを見逃していますが、今は残っている髪の毛を引き裂いています.
では、新しいユーザーがタブで次の行に移動するだけで行を追加することは可能ですか? 新しい行のカスケード コンボ ボックスを接続するために何か特別なことが必要ですか?
ありがとう!
これが私のXAMLです(本質的にはそれを取り除いた後の疑似コードなので、スペルミスは気にしないでください):
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication2"
mc:Ignorable="d"
d:DesignHeight="768"
d:DesignWidth="1024">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<StackPanel>
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Prices}"
SelectedItem="{Binding SelectedPrice}"
CanUserAddRows="True">
<DataGrid.Columns>
<!-- Price Group -->
<DataGridTemplateColumn MinWidth="120"
Header="Price Group">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cboPriceGroup"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.PriceGroups}"
DisplayMemberPath="Name"
SelectedItem="{Binding PriceGroupObject, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Option 1 -->
<DataGridTemplateColumn MinWidth="120"
Header="Option1">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cboOption1"
ItemsSource="{Binding PriceGroupObject.Options1}"
DisplayMemberPath="Code"
SelectedValuePath="Id"
SelectedValue="{Binding Option1Id, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Option 2 -->
<DataGridTemplateColumn MinWidth="120"
Header="Option2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cboOption2"
ItemsSource="{Binding PriceGroupObject.Options2}"
DisplayMemberPath="Code"
SelectedValuePath="Id"
SelectedValue="{Binding Option2Id, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Price -->
<DataGridTemplateColumn MinWidth="120"
Header="Price">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="txtPrice"
Text="{Binding Price, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Grid>
ビューモデルは次のとおりです。
// ViewModelBase implements INotifyPropertyChanged
public class MainWindowViewModel : ViewModelBase
{
#region Declarations
// Comes From Backend.Services
private IPriceListService _PriceListService;
private ObservableCollection<Price> _Prices;
private Price _SelectedPrice;
private IEnumerable<PriceGroup> _PriceGroups;
private PriceGroup _SelectedPriceGroup;
// Same for Options1, Options2
#endregion
#region Properties
public ObservableCollection<Price> Prices
{
get { return _Prices; }
set
{
if (_Prices != value)
{
_Prices = value;
OnPropertyChanged("Prices");
}
}
}
public Price SelectedPrice
{
get { return _Price; }
set
{
if (_Price != value)
{
_Price = value;
OnPropertyChanged("SelectedPrice");
}
}
}
// Same for PriceGroups, Options1, Options2
#endregion
#region Constructor
public MainViewModel()
: this(new FakePriceListService())
{
}
// Constructor
public MainViewModel(IPriceListService priceListService)
{
_PriceListService = priceListService;
InitializeViewModel();
}
protected override void InitializeViewModel()
{
// Test ID
LoadFuturesPrices(12345);
LoadPriceGroups();
base.InitializeViewModel();
}
#endregion
#region Methods
void LoadFuturesPrices(short FinancialPeriodId)
{
Prices = _PriceListService.GetFuturesPriceList(FinancialPeriodId);
}
void LoadPriceGroups()
{
PriceGroups = _PriceListService.GetPriceGroups();
}
void PriceGroupSelected(string PriceGroupId)
{
SelectedPriceGroup = (from p in PriceGroups where p.Name == PriceGroupId select p).SingleOrDefault();
}
#endregion
}