Disable grid before event fire WPF
Asked Answered
F

1

6

I'm using telerik RadGridView in my WPF application. One of the column has the following functionality,

When the user changes the value of the column a command is fired as a event and a pop is shown. Using the pop up result(Yes or No) i'm updating the collection.

Now i'm facing an issue here.

Issue:

The user is changing the value of that column in one of the row and before the alert appears he is changing in another row of same column. So the application works in a different way and functionality collapses.

Work Tried:

I tried to disable the grid once the event fires and enable after the function is complete. But still the user is very fast even before the event triggers he is changing the value.

XAML:

<telerik:GridViewDataColumn Name="grdItemBuildColumn" DataMemberBinding="{Binding Build, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnlyBinding="{Binding IsEnable, Mode=OneWay, UpdateSourceTrigger= PropertyChanged}">
<telerik:GridViewDataColumn.CellEditTemplate>                                                        <DataTemplate>
<telerik:RadMaskedNumericInput Value="{Binding Build, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Mask="#1.0" Placeholder=" " 
TextMode="PlainText" AllowInvalidValues="False" IsClearButtonVisible="False" AutoFillNumberGroupSeparators="False"ext:MaskedInputExtensions.Minimum="0" SelectionOnFocus="SelectAll" AcceptsReturn="False">
<i:Interaction.Triggers>                                                                    <i:EventTrigger EventName="ValueChanged">
<i:InvokeCommandAction Command="{Binding BuidValueChangedCommand, Source={StaticResource MarketSeriesViewModel}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</telerik:RadMaskedNumericInput>
</DataTemplate>
</telerik:GridViewDataColumn.CellEditTemplate>
</telerik:GridViewDataColumn>

Command:

public ICommand BuidValueChangedCommand { get { return new RelayCommand(BuildValueChanged); } }

ViewModel:

    private void BuildValueChanged()
    {
    // Ask confirmation for delete.
    if (ShowMessages.MessageBox("This will be removed from the collection", "Application"))
      {
         DeleteItem(SelectedItem.Id)
      }
    else
      {
        Item bo = RestoreBuild(SelectedItem);
        SelectedItem = bo;
      }
    }

I just need something like restricting the user not to change the second value until the event triggers and he selects something(Yes/No) from the popup.

Can someone help me with this?

Frech answered 19/2, 2016 at 7:26 Comment(6)
I suggest you to create a property IsGridEnabled in your ViewModel, and at the beginning of command set IsGridEnabled=false, at the end of command set IsGridEnabled=false. And, of course, bind your grid.IsEnabled to this propertyGetaway
@ВасилийШапенко : Tried that but the user changes the value even before the event(command) gets fired.Frech
Does your viewModel use INotifyPropertyChanged?Ameliorate
@Ameliorate : YesFrech
@SanthoshKumar how is user changing other values before command executes? copy-paste more than one cell at a time? or just the command is executing after a delay?Perce
@KyloRen : The use the application very fast. No copy or paste. Command is executing after a delay. Within the delay they keyin other values too.Frech
P
3

please try the next:

Xaml

<Grid>
    <telerik:RadBusyIndicator IsBusy="{Binding ImBusy, UpdateSourceTrigger=PropertyChanged}">
        <telerik:RadGridView Margin="2"
                         ItemsSource="{Binding ChannelRuleMappings}"
                         SelectionUnit="FullRow"
                         SelectionMode="Extended" AutoGenerateColumns="False"
                         IsFilteringAllowed="False">
            <telerik:RadGridView.Columns>

                <telerik:GridViewDataColumn Name="grdItemBuildColumn" DataMemberBinding="{Binding Build, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnlyBinding="{Binding IsEnable, Mode=OneWay, UpdateSourceTrigger= PropertyChanged}">
                    <telerik:GridViewDataColumn.CellEditTemplate>
                        <DataTemplate>
                            <telerik:RadMaskedNumericInput Value="{Binding Build, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Mask="#1.0" Placeholder="*" 
                                                       TextMode="PlainText" 
                                                           UpdateValueEvent="LostFocus"
                                                           AllowInvalidValues="False" IsClearButtonVisible="False" AutoFillNumberGroupSeparators="False" 
                                                       maskedInput:MaskedInputExtensions.Minimum="0" SelectionOnFocus="SelectAll" AcceptsReturn="False">
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="ValueChanged">
                                        <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                                        AncestorType={x:Type telerik:RadGridView}}, Path=DataContext.BuidValueChangedCommand}"/>
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                            </telerik:RadMaskedNumericInput>
                        </DataTemplate>
                    </telerik:GridViewDataColumn.CellEditTemplate>
                </telerik:GridViewDataColumn>

            </telerik:RadGridView.Columns>
        </telerik:RadGridView>
    </telerik:RadBusyIndicator>
</Grid>

VM and models

//GridView VM - screen is a simple implementation of the INPC
public class StackOptimizerChannelRulesViewModel : Screen
{
    //provides values for grid view items source collection
    private readonly IStackOptimizerStep _step;
    //IUserInteractionService  is a simple implementation of the massage box service
    private readonly IUserInteractionService _interactionService;
    private bool _imBusy;

    public StackOptimizerChannelRulesViewModel(IStackOptimizerStep step, IUserInteractionService interactionService)
    {
        _step = step;
        _interactionService = interactionService;
        DisplayName = "Channels Rules";
        ChannelRuleMappings = new ObservableCollection<ChannelRuleMappingModelBase>();
    }

    protected override void OnInitialize()
    {
        base.OnInitialize();
        Init();
    }

    public ObservableCollection<ChannelRuleMappingModelBase> ChannelRuleMappings { get; set; }

    //allows to show the vbusy indicator
    public bool ImBusy
    {
        get { return _imBusy; }
        set
        {
            _imBusy = value;
            NotifyOfPropertyChange(()=>ImBusy);
        }
    }

    private ICommand _cmd;
    public ICommand BuidValueChangedCommand
    {
        get { return _cmd ?? (_cmd = new ActionCommand(BuildValueChanged)); }
    }

    private void BuildValueChanged()
    {
        ImBusy = true;
        // Ask confirmation for delete.
        if (_interactionService.AskYesNo("This will be removed from the collection"))
        {
            //Add yor logic on yes
            ImBusy = false;
        }
        else
        {
            //Add yor logic on no
            ImBusy = false;
        }
    }

    private void Init()
    {
        var channelRuleMappings = _step.GetRulesForChannels();
        if (channelRuleMappings != null)
            channelRuleMappings.ForEach(parameter => ChannelRuleMappings.Add(new ChannelRuleMappingModel(parameter, _interactionService)));
    }
}

//Row VM base 
public class ChannelRuleMappingModelBase : PropertyChangedBase
{
    private string _name;
    private readonly IUserInteractionService _interactionService;
    private StackOptimizerSelectionRules _stackOptimizerSelectedRule;
    private object _build;

    public ChannelRuleMappingModelBase(string channelName, IUserInteractionService interactionService)
    {
        _name = channelName;
        _interactionService = interactionService;
    }

    public virtual string Name
    {
        get { return _name; }
    }

    public virtual StackOptimizerSelectionRules StackOptimizerSelectedRule
    {
        get { return _stackOptimizerSelectedRule; }
        set
        {
            _stackOptimizerSelectedRule = value;
            NotifyOfPropertyChange(() => StackOptimizerSelectedRule);
        }
    }

    public object Build
    {
        get { return _build; }
        set
        {
            _build = value;
            NotifyOfPropertyChange(() => Build);
        }
    }
}

//Row VM
public class ChannelRuleMappingModel : ChannelRuleMappingModelBase
{
    private StackOptimizerSelectionRules _stackOptimizerSelectedRule;
    private ISpectrumRuleParameter _ruleMapping;

    public ChannelRuleMappingModel(ISpectrumRuleParameter ruleMapping, IUserInteractionService interactionService):
        base(ruleMapping.PolarizationKey.Name, interactionService)
    {
        _ruleMapping = ruleMapping;
        _stackOptimizerSelectedRule = _ruleMapping.Rule;

    }

    public override StackOptimizerSelectionRules StackOptimizerSelectedRule
    {
        get { return _stackOptimizerSelectedRule; }
        set
        {
            _stackOptimizerSelectedRule = value;
            NotifyOfPropertyChange(() => StackOptimizerSelectedRule);
            UpdateOriginalRuleMapping(StackOptimizerSelectedRule);
        }
    }

    private void UpdateOriginalRuleMapping(StackOptimizerSelectionRules stackOptimizerSelectedRule)
    {
        if(_ruleMapping == null) return;
        _ruleMapping.Rule = stackOptimizerSelectedRule;
    }
}

Small explanation:

  1. A busy indicator was added(telerik's RadBusyIndicator).
  2. The command was defined inside the row's parent(RadGridView) ViewModel.
  3. A relative binding is used in order to point to the command inside the RadGridView's ViewModel.
  4. Each time user change the value of the RadMaskedNumericInput and move the focus to the other place(tab was pressed or mouse was down to some other control) due to UpdateValueEvent="LostFocus" the "ValueChanged" event is raised the trigger will start the command, this command will cause the BusyIndicator to be shown, the BusyIndicator will lock the grid view(RadGridView).

How it looks like: here is the picture

Let me know if you need more explanation to the code.

Regards.

Peake answered 24/2, 2016 at 8:49 Comment(6)
But still at a rare time i'm able to edit next row value before the alert appears.Frech
@SanthoshKumar you should use the UpdateValueEvent="LostFocus". did you use this property?Peake
When adding the event, the alert is thrown only when the user tries to change the second value. If the user changes only one value the alert is not thrown. can you get me? I need like when the user changes the value the alert should be thrown .Frech
@SanthoshKumar in the current case the alert will be shown when a TextBox its value was changed will lost the focus. If you want to show the alert each time you type a char, just remove this property(UpdateValueEvent="LostFocus") or use another event instead the "LostFocus".Peake
Used UpdateValueEvent="PropertyChanged" and that worked well. Thakns for your excellent time and reply. CheersFrech
Can you please look into this? #35745707Frech

© 2022 - 2024 — McMap. All rights reserved.