gpt4 book ai didi

c# - 复选框选中事件触发多次 wpf mvvm

转载 作者:行者123 更新时间:2023-12-03 10:27:38 25 4
gpt4 key购买 nike

我在 DataGrid 中获得了复选框列,该列在特定行中填充实时下载百分比,由 caseRefNo 过滤。我需要添加复选框更改事件以执行某些操作。我用了InvokeCommandAction将 Action 添加到复选框。
我意识到当我第一次单击复选框时,没关系,只触发一次。但是当我第二次点击同一个复选框时触发了两次。第三次点击同一个复选框,它触发了四次。相当可怕,很难弄清楚。

这是我的 View 模型代码

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);
}
}

这是上述 View 模型的 XAML。
<Window x:Class="EmployeeManager.View.DataGridDownload"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Title="DataGridDownload" Height="600" Width="790">
<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding TransView}" 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 Name="abcdef"
Content="Please Select" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction CommandParameter="{Binding ElementName=abcdef}" Command="{Binding DataContext.CheckCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}" />
</i:EventTrigger>
</i: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>
<Label Content="{Binding UpdatePercentage}" HorizontalAlignment="Left" Background="Blue" Foreground="White" Margin="10,10,0,0" VerticalAlignment="Top" Width="338" Height="30">

</Label>
<Button Content="Button" HorizontalAlignment="Left" Margin="672,20,0,0" VerticalAlignment="Top" Width="75"/>

</Grid>
</Window>

这是我的模型
    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; }
}

这是我的表格的图片

enter image description here

是因为 DispatcherTimer 吗?欢迎所有建议。

df

最佳答案

enter image description here

我想我在你之前的问题中留下了一条评论,说将你的收藏包装到 CollectionView 是很臭的。

无论如何, TransView.Refresh();导致您的代码出现问题。
TransView.Refresh 将为每个选中的复选框触发“选中”事件。刷新基本上要求 wpf 引擎将所有数据重新填充到您的 CollectionView 中,然后每个选中的复选框将再次触发选中的事件。

尝试将 dispatchTimer.Interval 设置为更短的时间,例如300. 您应该能够看到复选框中的“勾号”不断闪烁,因为 TransView.Refresh。

实际上,我不知道您为什么不将 TransList 绑定(bind)到 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>

关于c# - 复选框选中事件触发多次 wpf mvvm,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32762963/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com