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

C# 选中复选框事件触发多次wpf mvvm,c#,wpf,checkbox,mvvm,C#,Wpf,Checkbox,Mvvm,我在DataGrid中得到了一个复选框列,它在特定行中填充实时下载百分比,并通过caseRefNo进行过滤。我需要添加复选框更改事件来执行一些操作。我使用InvokeCommandAction将操作添加到复选框中。 我意识到当我第一次点击复选框时,它是ok的,并且只触发一次。但第二次单击同一复选框时会触发两次。第三次单击同一复选框时,会触发四次。很可怕,也很难弄明白 这是我的viewmodel代码 public class DataGridDownloadViewModel:BindableBa

我在DataGrid中得到了一个复选框列,它在特定行中填充实时下载百分比,并通过caseRefNo进行过滤。我需要添加复选框更改事件来执行一些操作。我使用
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>