Can I handle PageIndexChanged using custom binding?

10 posts, 0 answers
  1. AEDT developer
    AEDT developer avatar
    9 posts
    Member since:
    May 2012

    Posted 22 Jun 2012 Link to this post

    I am using MVVM and would like to move the event handling out of the view. I am trying to handle the PageIndexChanged event of the RadDataPager by using a custom binding. The handler sets the ItemsSource of a RadGridView and the ItemCount of the pager (i.e. I am doing the paging myself). To set it up I use a style:

        <Window.Resources>
            <Style TargetType="{x:Type telerik:RadDataPager}"
                   x:Key="indexChangedStyle">
                <Setter Property="local:PageIndexChangedBehavior.SetPageIndexChanged"
                        Value="True" />
            </Style>
        </Window.Resources>

            <telerik:RadDataPager x:Name="dataPager"
                                  Grid.Row="1"
                                  DisplayMode="All"
                                  PageSize="10"
                                  Style="{StaticResource indexChangedStyle}">

    In the custom behavior I do this:
            public static readonly DependencyProperty SetPageIndexChangedProperty =
                DependencyProperty.RegisterAttached(
                "SetPageIndexChanged",
                typeof(bool),
                typeof(PageIndexChangedBehavior),
                new UIPropertyMetadata(true, OnSetPageIndexChanged));

            private static void OnSetPageIndexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                RadDataPager pager = obj as RadDataPager;
                if (pager == null)
                    return;

                if (e.NewValue is bool == false)
                    return;

                if ((bool)e.NewValue)
                    pager.PageIndexChanged += pager_PageIndexChanged;
                else
                    pager.PageIndexChanged -= pager_PageIndexChanged;
            }

    OnSetPageIndexChanged() never gets called. Will this methodology work? Is there a better way?

    Thanks.

    Andrea
  2. Ivan Ivanov
    Admin
    Ivan Ivanov avatar
    1128 posts

    Posted 26 Jun 2012 Link to this post

    Hi,

    Personally, I would use the Event-to-Command pattern in such scenarios. Here is an article that illustrates how to implement Event-to-Command with Blend's EventTriggers. Please, refer to it and let us know whether such an approach is a viable one for your case. I will be glad to provide additional help with the implementation, in case it is needed. As for your current solution, it is difficult for us to carry out a detailed debug session, while having so limited information on you case. Will it be possible for you to send us a simple runnable project, if you have decided to stick to your current approach?

    Kind regards,
    Ivan Ivanov
    the Telerik team
    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
  3. UI for WPF is Visual Studio 2017 Ready
  4. AEDT developer
    AEDT developer avatar
    9 posts
    Member since:
    May 2012

    Posted 27 Jun 2012 Link to this post

    Hi,

    I now have the behavior working, but you are correct that direct handling an event in the view model would be better. Unfortunately, I do not see how to use the Event-to-Command pattern as described in the article.

    The PageIndexChanged of the RadDataPager is not a routed event (at least that is one of the error messages that I got). Also InvokeCommandAction does not have a Command, it has a CommandName. Also, I am not clear on how the event parameters are dealt with.

    Here is basically what I have been trying...

            <telerik:RadDataPager x:Name="dataPager"
                                  Grid.Row="1"
                                  DisplayMode="All"
                                  PageSize="10">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="PageIndexChanged">
                        <i:InvokeCommandAction CommandName="<what goes here?>"
                    </i:EventTrigger>
                </i:Interaction.Triggers>

                ...


    It would be nice to see a complete example with the RadDataPager.

    Thanks.

  5. Ivan Ivanov
    Admin
    Ivan Ivanov avatar
    1128 posts

    Posted 29 Jun 2012 Link to this post

    Hi Andrea,

    I have prepared a sample project for you. Please refer to it, so that we can discuss on it.

    All the best,
    Ivan Ivanov
    the Telerik team
    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
  6. AEDT developer
    AEDT developer avatar
    9 posts
    Member since:
    May 2012

    Posted 02 Jul 2012 Link to this post

    Hi Ivan,

    From your example I cannot see how to do what I need. Here is an example from the Telerik web site. I would like to do this using MVVM, i.e. move the handler into the view model. Basically, I need to set the ItemsSource when the event fires. How do I get access to the sender and PageIndexChangedEventArgs?

    public partial class UnboundModeSample : UserControl
    {
        private List<int> data;
        public UnboundModeSample()
        {
            InitializeComponent();
            this.data = Enumerable.Range( 0, 100 ).ToList();
            this.radDataPager.ItemCount = data.Count;
            this.listBox.ItemsSource = this.data.Take( this.radDataPager.PageSize ).ToList();
        }
        private void radDataPager_PageIndexChanged( object sender, PageIndexChangedEventArgs e )
        {
            if ( this.data != null )
            {
                this.listBox.ItemsSource = this.data
                   .Skip( e.NewPageIndex * this.radDataPager.PageSize )
                   .Take( this.radDataPager.PageSize ).ToList();
            }
        }
    }

    Thank you.
  7. Ivan Ivanov
    Admin
    Ivan Ivanov avatar
    1128 posts

    Posted 03 Jul 2012 Link to this post

    Hello,

    There is no easy way to pass event's arguments as CommandParameter using Blend's EventTrigger. You can either define an attached behavior that handles the event, or use some external MVVM framework that supports this. Here is a discussion that addresses the latter option. However, in both cases, passing this ListBox to your ViewModel won't be a good MVVM practice. In my opinion you should try to work with properties of your VM, rather that with visual objects. Please let us know in case you need any additional assistance with these.

    All the best,
    Ivan Ivanov
    the Telerik team
    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
  8. AEDT developer
    AEDT developer avatar
    9 posts
    Member since:
    May 2012

    Posted 03 Jul 2012 Link to this post

    Hi Ivan,

    With my custom behavior solution the handler is in the view, but it is attached to an event in the view model. The view model does not know about the grid, pager or anything else in the view. The behavior just attaches the handler to the view model. This does leave code in the code behind, but I am not sure how to avoid this.

    The handler in the view calls into the view model to get the next page. Since I am doing custom paging I need to retrieve the next page myself. Seems a bit convoluted to do something simple, but it separates the view and view model. I am not sure if this qualifies for, "you should try to work with properties of your VM, rather that with visual objects". I can see no other way to load the next page. If you see some glaring fault in this, please let me know.

    The link that you sent is helpful. It appears that even if we adopt a framework or write extra code we do not gain a lot over using a behavior unless we do this many times.

    Thanks for your help.

    Andrea
  9. Ivan Ivanov
    Admin
    Ivan Ivanov avatar
    1128 posts

    Posted 04 Jul 2012 Link to this post

    Hello,

    If the attached behavior approach, works in your case, I believe that there should not be any concerns against using it. Actually, it is a very common technique for MVVM compatible event handling. You have mentioned that there is some code left in the codebehind. You can share a snippet or a project, so that we can try to think of how to tackle this problem.

    Kind regards,
    Ivan Ivanov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  10. AEDT developer
    AEDT developer avatar
    9 posts
    Member since:
    May 2012

    Posted 05 Jul 2012 Link to this post

    Ivan,

    Here is the code that I have in the code behind:

            public MainWindow()
            {
                InitializeComponent();
                this.mainWindowViewModel.PagerPageIndexChanged += (sender, e) =>
                    {
                        int count;

                        this.gridView.ItemsSource = this.mainWindowViewModel.GetOperations(
                            e.NewPageIndex * dataPager.PageSize,
                            dataPager.PageSize,
                            out count);

                        this.dataPager.ItemCount = count;
                    };

     
                // needed to load the first page - as far as I can figure out...

                this.mainWindowViewModel.FirePageIndexChanged(this, new PageIndexChangedEventArgs(0, 0));
            }

    In the behavior the handler in the view model is attached...
            public static void OnSetPageIndexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                RadDataPager pager = obj as RadDataPager;
                if (pager == null)
                    return;

                if (e.NewValue is bool == false)
                    return;

                if ((bool)e.NewValue)
                    pager.PageIndexChanged += pager_PageIndexChanged;
                else
                    pager.PageIndexChanged -= pager_PageIndexChanged;
            }

            private static void pager_PageIndexChanged(object sender, PageIndexChangedEventArgs e)
            {
                MainWindowViewModel viewModel = ((MainWindow)App.Current.MainWindow).ViewModel;
                viewModel.FirePageIndexChanged(sender, e);
            }

    If you can think of a way of moving this all to the view model, that would be great. I do not see another reasonable way without letting the view model know details about the view. But, I am very new to both WPF and MVVM. This all seems very cumbersome to me...

    Thanks for taking a look.

    Andrea

  11. Ivan Ivanov
    Admin
    Ivan Ivanov avatar
    1128 posts

    Posted 06 Jul 2012 Link to this post

    Hi,

    You can try passing the RadGridView instance as a parameter for this behavior and handle this logic internally. However, I am a little bit confused about the setting of RadGridView's ItemsSource on pager's PageIndexChanged. Do you have any concerns against binding it to the pager's PagedSource property? In case it is possible for you to send us a simple demo, we will be glad to review it and give you some guidelines to get the most out of our controls. 

    Greetings,
    Ivan Ivanov
    the Telerik team
    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
Back to Top
UI for WPF is Visual Studio 2017 Ready