Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disable grid before event fire WPF

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?

like image 621
A Coder Avatar asked Feb 19 '16 07:02

A Coder


1 Answers

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.

like image 98
Ilan Avatar answered Sep 29 '22 15:09

Ilan