复选框检查事件触发多次wpf mvvm

时间:2015-09-24 13:42:20

标签: c# wpf checkbox mvvm

我在DataGrid中有一个复选框列,它填充特定行的实时下载百分比,由caseRefNo过滤。我需要添加复选框更改事件来执行某些操作。我使用InvokeCommandAction将操作添加到复选框。 我意识到,当我第一次点击该复选框时,它是正常的并且只触发一次。但是当我在同一个复选框上第二次点击时会触发两次。第三次点击同一个复选框时,它会触发四次。非常可怕而且难以弄明白。

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

这是上面视图模型的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

1 个答案:

答案 0 :(得分:2)

enter image description here

我想我在你上一个问题中留下了一条评论,说你将你的收藏包装到CollectionView是非常臭的。

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

尝试将dispatchTimer.Interval设置为更短的时间,例如300.你应该能够看到复选框中的“勾号”,保持轻击TransView.Refresh的becoz。

实际上,我不知道你为什么不将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>