我遇到问题,当CheckBox中的选项发生变化时,我需要在Amount属性中添加或减去Quantity属性值,这在今天更改所选行时完成
我做错了什么?
MainWindow.xaml
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="5">
<Label Content="Sum of selected items: " />
<TextBlock Text="{Binding Amount}" Grid.Row="0" VerticalAlignment="Center" />
</StackPanel>
<DataGrid Grid.Row="1" Margin="5"
ColumnWidth="*"
AutoGenerateColumns="False"
SelectionMode="Single"
HorizontalContentAlignment="Center"
ItemsSource="{Binding MyDataList}"
SelectedItem="{Binding MyData, UpdateSourceTrigger=PropertyChanged}"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto" >
<DataGrid.Columns>
<DataGridTemplateColumn Width="30">
<DataGridTemplateColumn.Header>
<Grid>
<CheckBox IsChecked="{Binding DataContext.AllSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"/>
</Grid>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!--<Viewbox Height="25">-->
<CheckBox IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, Mode=TwoWay}"/>
<!--</Viewbox>-->
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="*" IsReadOnly="True"/>
<DataGridTextColumn Header="Quantity" Binding="{Binding Quantity, StringFormat=N2}" Width="160" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
类 (ViewModelBase实现INotifyPropertyChanged)
public class MyDataClass: ViewModelBase
{
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
_isSelected = value;
OnPropertyChanged();
}
}
public string Description { get; set; }
public double Quantity { get; set; }
}
MainViewModel
public class MainViewModel : ViewModelBase
{
private ObservableCollection<MyDataClass> _myDataList;
private MyDataClass _myData;
public MainViewModel()
{
var list = new List<MyDataClass>
{
new MyDataClass { Description = "Item 01", Quantity = 20, IsSelected = false },
new MyDataClass { Description = "Item 02", Quantity = 50, IsSelected = false },
new MyDataClass { Description = "Item 03", Quantity = 60, IsSelected = false }
};
MyDataList = new ObservableCollection<MyDataClass>(list);
}
public ObservableCollection<MyDataClass> MyDataList
{
get => _myDataList;
set
{
_myDataList = value;
OnPropertyChanged();
OnPropertyChanged(nameof(Amount));
}
}
public MyDataClass MyData
{
get => _myData;
set
{
_myData = value;
OnPropertyChanged();
OnPropertyChanged(nameof(Amount));
}
}
public double Amount => MyDataList.Where(x=>x.IsSelected).Sum(x => x.Quantity);
}
答案 0 :(得分:2)
另一种方法是向所有复选框添加命令,因此每当您单击复选框时,它将触发命令
<CheckBox Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type DataGrid}},
Path=DataContext.CheckCommand}" IsChecked="{Binding DataContext.AllSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"/>
MainViewModel
private ObservableCollection<MyDataClass> _myDataList;
private MyDataClass _myData;
public ICommand CheckCommand { get; set; }
public MainViewModel()
{
var list = new List<MyDataClass>
{
new MyDataClass { Description = "Item 01", Quantity = 20, IsSelected = false },
new MyDataClass { Description = "Item 02", Quantity = 50, IsSelected = false },
new MyDataClass { Description = "Item 03", Quantity = 60, IsSelected = false }
};
MyDataList = new ObservableCollection<MyDataClass>(list);
CheckCommand = new RelayCommand(()=> { Amount = MyDataList.Where(x => x.IsSelected).Sum(x => x.Quantity); });
}
public ObservableCollection<MyDataClass> MyDataList
{
get => _myDataList;
set
{
_myDataList = value;
OnPropertyChanged();
}
}
我的RelayCommand类
public class RelayCommand : ICommand
{
private Action mAction;
public event EventHandler CanExecuteChanged = (sender, e) => { };
public RelayCommand(Action action)
{
mAction = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
mAction();
}
}
答案 1 :(得分:1)
您需要为每个项目收听MyDataClass.PropertyChanged
,如果IsSelected
属性发生变化,请致电OnPropertyChanged(nameof(Amount))
。
public MainViewModel()
{
var list = new List<MyDataClass>
{
new MyDataClass { Description = "Item 01", Quantity = 20, IsSelected = false },
new MyDataClass { Description = "Item 02", Quantity = 50, IsSelected = false },
new MyDataClass { Description = "Item 03", Quantity = 60, IsSelected = false }
};
foreach (var item in list)
{
item.PropertyChanged += OnItemPropertyChanged;
}
MyDataList = new ObservableCollection<MyDataClass>(list);
}
void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsSelected") OnPropertyChanged(nameof(Amount));
}
请注意,代码可能包含小错字,我只是在纯文本编辑器中编写。
如果您动态添加/删除项目,则需要处理这些项目的更改通知订阅(例如@Marisa已回答)。
答案 2 :(得分:1)
您需要挂钩CollectionChanged事件处理程序以获取数据集合,然后挂钩到每个项目的PropertyChanged。
请注意,您还需要更改初始化observable集合的方式;像在原始样本中那样初始化它意味着该集合不会获得PropertyChanged事件处理程序,因此不会通知集合成员已对其属性应用了更改。
public class MainViewModel : ViewModelBase
{
private ObservableCollection<MyDataClass> _myDataList;
public MainViewModel()
{
var list = new List<MyDataClass>
{
new MyDataClass {Description = "Item 01", Quantity = 20, IsSelected = false},
new MyDataClass {Description = "Item 02", Quantity = 50, IsSelected = false},
new MyDataClass {Description = "Item 03", Quantity = 60, IsSelected = false}
};
MyDataList = new ObservableCollection<MyDataClass>();
foreach (var myDataClass in list)
{
MyDataList.Add(myDataClass);
}
}
public ObservableCollection<MyDataClass> MyDataList
{
get => _myDataList;
set
{
_myDataList = value;
MyDataList.CollectionChanged += MyDataList_CollectionChanged; // sets up the collection so it will auto-hookup each element
OnPropertyChanged();
}
}
private void MyDataList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
foreach (MyDataClass item in e.NewItems)
item.PropertyChanged += MyData_PropertyChanged;
if (e.OldItems != null)
foreach (MyDataClass item in e.OldItems)
item.PropertyChanged -= MyData_PropertyChanged;
OnPropertyChanged(nameof(MyDataList));
}
private void MyData_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(MyDataClass.IsSelected):
OnPropertyChanged(nameof(Amount));
break;
}
}
public double Amount => MyDataList.Where(x => x.IsSelected).Sum(x => x.Quantity);
}