C# 选中复选框事件触发多次wpf mvvm
我在DataGrid中得到了一个复选框列,它在特定行中填充实时下载百分比,并通过caseRefNo进行过滤。我需要添加复选框更改事件来执行一些操作。我使用C# 选中复选框事件触发多次wpf mvvm,c#,wpf,checkbox,mvvm,C#,Wpf,Checkbox,Mvvm,我在DataGrid中得到了一个复选框列,它在特定行中填充实时下载百分比,并通过caseRefNo进行过滤。我需要添加复选框更改事件来执行一些操作。我使用InvokeCommandAction将操作添加到复选框中。 我意识到当我第一次点击复选框时,它是ok的,并且只触发一次。但第二次单击同一复选框时会触发两次。第三次单击同一复选框时,会触发四次。很可怕,也很难弄明白 这是我的viewmodel代码 public class DataGridDownloadViewModel:BindableBa
InvokeCommandAction
将操作添加到复选框中。
我意识到当我第一次点击复选框时,它是ok的,并且只触发一次。但第二次单击同一复选框时会触发两次。第三次单击同一复选框时,会触发四次。很可怕,也很难弄明白
这是我的viewmodel代码
public class DataGridDownloadViewModel:BindableBase
{
public ObservableCollection<tblTransaction> TransList { get; private set; }
public DispatcherTimer dispatchTimer = new DispatcherTimer();
public CollectionView TransView { get; private set; }
public DelegateCommand<object> CheckCommand { get; set; }
private String _UpdatePer;
public String UpdatePercentage
{
get { return _UpdatePer; }
set { SetProperty(ref _UpdatePer, value); }
}
private string _caseId;
public string CaseID
{
get { return _caseId; }
set { SetProperty(ref _caseId, value); }
}
private string _isChecked;
public string isChecked
{
get { return _isChecked; }
set { SetProperty(ref _isChecked, value); }
}
private bool CanExecute(object args)
{
return true;
}
private void CheckBoxChecker(object args)
{
//Should Work Here
// Totally not coming to this function
CheckBox chk = (CheckBox)args;
string thichintae = chk.Name.ToString();
Console.WriteLine(thichintae);
}
public DataGridDownloadViewModel(List<tblTransaction> model)
{
CheckCommand = new DelegateCommand<object>(CheckBoxChecker, CanExecute);
dispatchTimer.Interval = TimeSpan.FromMilliseconds(3000);
dispatchTimer.Tick += dispatchTimer_Tick;
BackGroundThread bgT = Application.Current.Resources["BackGroundThread"] as BackGroundThread;
bgT.GetPercentChanged += (ss, ee) =>
{
UpdatePercentage = bgT.local_percentage.ToString();
};
bgT.GetCaseID += (ss, ee) =>
{
CaseID = bgT.local_caseRef;
};
TransList =new ObservableCollection<tblTransaction>(model);
TransView = GetTransCollectionView(TransList);
TransView.Filter = OnFilterTrans;
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var cancellationTokenSource = new CancellationTokenSource();
dispatchTimer.Start();
}
private void dispatchTimer_Tick(object sender, EventArgs e)
{
UpdateDataGrid();
}
public void UpdateDataGrid()
{
foreach (tblTransaction tran in TransList)
{
if (tran.caseRefNo == CaseID)
{
tran.incValue = int.Parse(UpdatePercentage);
}
else
{
tran.incValue = tran.incValue;
}
}
TransView.Refresh();
}
bool OnFilterTrans(object item)
{
var trans = (tblTransaction)item;
return true;
}
public CollectionView GetTransCollectionView(ObservableCollection<tblTransaction> tranList)
{
return (CollectionView)CollectionViewSource.GetDefaultView(tranList);
}
}
这是我的照片
是因为调度员吗?欢迎所有建议
df
我想我在你之前的问题中留下了一条评论,说将你的收藏包装到CollectionView很难闻
无论如何,TransView.Refresh();是导致代码出现问题的原因。
刷新将为每个选中的复选框触发“选中”事件。刷新基本上要求wpf引擎将所有数据重新填充到CollectionView中,然后,每个选中的复选框将再次触发选中的事件
尝试将dispatchTimer.Interval设置为更短的时间,例如300。由于TransView.Refresh的原因,您应该能够在复选框中看到“勾选”
实际上,我不知道为什么不将TransList绑定到DataGrid,并在UpdateDataGrid方法上调用BeginInvoke
演示ObservableCollection的工作原理
我使用ObservableCollection重新编写了部分代码。至少让事情更好地符合MVVM模型
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainViewModel : ViewModelBase
{
public ObservableCollection<TblTransaction> TransList { get; private set; }
public DispatcherTimer DispatchTimer = new DispatcherTimer();
public MainViewModel()
{
var model = new ObservableCollection<TblTransaction>();
for (int i = 0; i < 5; i++)
{
model.Add(new TblTransaction { CaseRefNo = i.ToString(), IncValue = i, LongTime = DateTime.Now, SubjMatr = i.ToString() });
if (i == 3)
model[i].IsSelected = true;
}
DispatchTimer.Interval = TimeSpan.FromMilliseconds(200);
DispatchTimer.Tick += dispatchTimer_Tick;
TransList = model;
DispatchTimer.Start();
}
private void dispatchTimer_Tick(object sender, EventArgs e)
{
UpdateDataGrid();
}
public void UpdateDataGrid()
{
var ran = new Random();
foreach (var tran in TransList)
tran.IncValue = ran.Next(0, 100);
}
}
public class TblTransaction : ViewModelBase
{
private string caseRefNo;
private string subjMatr;
private int incValue;
private DateTime? longTime;
private bool isSelected;
public DelegateCommand<object> CheckCommand { get; set; }
public TblTransaction()
{
CheckCommand = new DelegateCommand<object>(CheckBoxChecker, (p) => true);
}
private void CheckBoxChecker(object args)
{
//Should Work Here
// Totally not coming to this function
//CheckBox chk = (CheckBox)args;
//string thichintae = chk.Name;
Console.WriteLine(args);
}
public string CaseRefNo
{
get { return caseRefNo; }
set
{
caseRefNo = value;
OnPropertyChanged();
}
}
public string SubjMatr
{
get { return subjMatr; }
set
{
subjMatr = value;
OnPropertyChanged();
}
}
public int IncValue
{
get { return incValue; }
set
{
incValue = value;
OnPropertyChanged();
}
}
public DateTime? LongTime
{
get { return longTime; }
set
{
longTime = value;
OnPropertyChanged();
}
}
public bool IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
OnPropertyChanged();
}
}
}
<Window x:Class="WpfTestProj.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:WpfTestProj"
xmlns:interact="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MainViewModel, IsDesignTimeCreatable=False}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding TransList}" AutoGenerateColumns="False" Margin="10,62,0,0" VerticalAlignment="Top" Height="497" Width="762">
<DataGrid.Columns>
<DataGridTextColumn Header="caseRefNo" Binding="{Binding CaseRefNo}" />
<DataGridTextColumn Header="subjMatr" Binding="{Binding SubjMatr}" />
<DataGridTextColumn Header="Download %" Binding="{Binding IncValue}" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Content="Please Select" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<interact:Interaction.Triggers>
<interact:EventTrigger EventName="Checked">
<interact:InvokeCommandAction CommandParameter="{Binding Path=CaseRefNo}" Command="{Binding Path=CheckCommand}" />
</interact:EventTrigger>
</interact:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding IncValue, UpdateSourceTrigger=PropertyChanged}" Background="Red" Foreground="White" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Content="Button" HorizontalAlignment="Left" Margin="672,20,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
公共抽象类ViewModelBase:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
[NotifyPropertyChangedInvocator]
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
var handler=PropertyChanged;
if(handler!=null)handler(这是新的PropertyChangedEventArgs(propertyName));
}
}
公共类MainViewModel:ViewModelBase
{
公共可观察集合TransList{get;private set;}
public dispatchermer dispatchetimer=new dispatchermer();
公共主视图模型()
{
var模型=新的ObservableCollection();
对于(int i=0;i<5;i++)
{
Add(新的TblTransaction{CaseRefNo=i.ToString(),IncValue=i,LongTime=DateTime.Now,submatr=i.ToString();
如果(i==3)
模型[i]。IsSelected=true;
}
DispatchTimer.Interval=TimeSpan.From毫秒(200);
DispatchTimer.Tick+=DispatchTimer\u Tick;
TransList=模型;
DispatchTimer.Start();
}
私有void dispatchTimer_Tick(对象发送方,事件参数e)
{
UpdateDataGrid();
}
public void UpdateDataGrid()
{
var ran=new Random();
foreach(翻译列表中的var tran)
tran.IncValue=ran.Next(01100);
}
}
公共类TblTransaction:ViewModelBase
{
私人字符串caseRefNo;
私有字符串submatr;
私人价值;
私人约会时间?长时间;
私人布尔当选;
公共DelegateCommand检查命令{get;set;}
公共TblTransaction()
{
CheckCommand=新的DelegateCommand(CheckBoxChecker,(p)=>true);
}
专用void CheckBoxChecker(对象参数)
{
//你应该在这里工作
//完全没有达到这个功能
//复选框chk=(复选框)参数;
//字符串thichintae=chk.Name;
控制台写入线(args);
}
公共字符串CaseRefNo
{
获取{return caseRefNo;}
设置
{
caseRefNo=值;
OnPropertyChanged();
}
}
公共字符串submatr
{
获取{return submatr;}
设置
{
submatr=值;
OnPropertyChanged();
}
}
公共价值
{
获取{return incValue;}
设置
{
incValue=值;
OnPropertyChanged();
}
}
公共日期时间?长时间
{
获取{return longTime;}
设置
{
长时间=价值;
OnPropertyChanged();
}
}
公选学校
{
获取{return isSelected;}
设置
{
isSelected=值;
OnPropertyChanged();
}
}
}
是的。。这条线没有必要。我现在要发表评论。我刚刚意识到,如果我去掉UpdateSourceTrigger=PropertyChanged in复选框,它只会触发一次。但当我刷新TransView时,检查消失了。我使用了observableCollection,但datagrid没有持续更新百分比值。我编辑了我的答案,根据您的代码添加了一个示例,以使其更符合MVVM模型。试着想象一下,您可以将WPF GUI中的每个组件(逻辑视图)分离成一个完整的单独会话。e、 g.您的主窗口将其VM作为MainViewModel,DataGrid将其VM作为ObservableCollection,每个DataRow将其VM作为TBLTTransaction。只需在您的项目中运行我的示例代码,您将看到下载百分比保持不变,红色标签保持更新(因为它是随机更新的。下一步)。如果遇到任何问题,请告诉我。
public class tblTransaction
{
public string caseRefNo { get;set;}
public string subjMatr { get; set; }
public int incValue { get; set; }
public DateTime? longTime { get; set; }
public bool IsSelected { get; set; }
}
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainViewModel : ViewModelBase
{
public ObservableCollection<TblTransaction> TransList { get; private set; }
public DispatcherTimer DispatchTimer = new DispatcherTimer();
public MainViewModel()
{
var model = new ObservableCollection<TblTransaction>();
for (int i = 0; i < 5; i++)
{
model.Add(new TblTransaction { CaseRefNo = i.ToString(), IncValue = i, LongTime = DateTime.Now, SubjMatr = i.ToString() });
if (i == 3)
model[i].IsSelected = true;
}
DispatchTimer.Interval = TimeSpan.FromMilliseconds(200);
DispatchTimer.Tick += dispatchTimer_Tick;
TransList = model;
DispatchTimer.Start();
}
private void dispatchTimer_Tick(object sender, EventArgs e)
{
UpdateDataGrid();
}
public void UpdateDataGrid()
{
var ran = new Random();
foreach (var tran in TransList)
tran.IncValue = ran.Next(0, 100);
}
}
public class TblTransaction : ViewModelBase
{
private string caseRefNo;
private string subjMatr;
private int incValue;
private DateTime? longTime;
private bool isSelected;
public DelegateCommand<object> CheckCommand { get; set; }
public TblTransaction()
{
CheckCommand = new DelegateCommand<object>(CheckBoxChecker, (p) => true);
}
private void CheckBoxChecker(object args)
{
//Should Work Here
// Totally not coming to this function
//CheckBox chk = (CheckBox)args;
//string thichintae = chk.Name;
Console.WriteLine(args);
}
public string CaseRefNo
{
get { return caseRefNo; }
set
{
caseRefNo = value;
OnPropertyChanged();
}
}
public string SubjMatr
{
get { return subjMatr; }
set
{
subjMatr = value;
OnPropertyChanged();
}
}
public int IncValue
{
get { return incValue; }
set
{
incValue = value;
OnPropertyChanged();
}
}
public DateTime? LongTime
{
get { return longTime; }
set
{
longTime = value;
OnPropertyChanged();
}
}
public bool IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
OnPropertyChanged();
}
}
}
<Window x:Class="WpfTestProj.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:WpfTestProj"
xmlns:interact="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MainViewModel, IsDesignTimeCreatable=False}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding TransList}" AutoGenerateColumns="False" Margin="10,62,0,0" VerticalAlignment="Top" Height="497" Width="762">
<DataGrid.Columns>
<DataGridTextColumn Header="caseRefNo" Binding="{Binding CaseRefNo}" />
<DataGridTextColumn Header="subjMatr" Binding="{Binding SubjMatr}" />
<DataGridTextColumn Header="Download %" Binding="{Binding IncValue}" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Content="Please Select" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<interact:Interaction.Triggers>
<interact:EventTrigger EventName="Checked">
<interact:InvokeCommandAction CommandParameter="{Binding Path=CaseRefNo}" Command="{Binding Path=CheckCommand}" />
</interact:EventTrigger>
</interact:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding IncValue, UpdateSourceTrigger=PropertyChanged}" Background="Red" Foreground="White" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Content="Button" HorizontalAlignment="Left" Margin="672,20,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>