When the SelectedItems attached property stops to work when I change the tab?

ComptonAlvaro 166 Reputation points
2021-02-24T14:55:26.59+00:00

I have a view and a view model. I have a datagrid that when I select a row, a textbox shows the value of the row. This is just to show if the selectedItems it is fired.

it works fine, but if I change to the other tab and back, it stops to work.

I am using Net 5.

My view:

<Window x:Class="TabControlError.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TabControlError"
        xmlns:vm="clr-namespace:TabControlError.ViewModels"
        xmlns:dp="clr-namespace:TabControlError.DependencyProperties"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>



    <Grid>
        <TabControl>
            <TabItem Header="Tab1">
                <Grid>
                    <TextBox Text="{Binding Text}" Width="100" Height="23" HorizontalAlignment="Left" VerticalAlignment="Top"/>

                    <DataGrid Margin="0,40,0,0"
                              ItemsSource="{Binding Numbers}"
                              SelectedItem="{Binding NumbersSelectedItem}"
                              dp:DataGridSelectedItemsDependencyProperty.SelectedItems="{Binding NumbersSelectedItems}">

                        <DataGrid.Columns>
                            <DataGridTextColumn Header="Number" Binding="{Binding Path=.}" Width="150"/>
                        </DataGrid.Columns>
                    </DataGrid>
                </Grid>
            </TabItem>

            <TabItem Header="Tab2"/>
        </TabControl>
    </Grid>
</Window>

My view model base:

using System.ComponentModel;
using System.Runtime.CompilerServices;



namespace TabControlError
{
    class ViewModelBase : INotifyPropertyChanging, INotifyPropertyChanged
    {
        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Administrative Properties

        /// <summary>
        /// Whether the view model should ignore property-change events.
        /// </summary>
        public virtual bool IgnorePropertyChangeEvents { get; set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// Raises the PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The name of the changed property.</param>
        //NOTA: el atributo CallerMemberName no es necesario, pero permite escribir OnPropertyChanged() en lugar de
        //OnPropertyChanged("SomeProperty"), por lo que se evita utilizar strings en el código.
        public virtual void RaisePropertyChangedEvent([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Raises the PropertyChanging event.
        /// </summary>
        /// <param name="propertyName">The name of the changing property.</param>
        //NOTA: el atributo CallerMemberName no es necesario, pero permite escribir OnPropertyChanged() en lugar de
        //OnPropertyChanged("SomeProperty"), por lo que se evita utilizar strings en el código.
        public virtual void RaisePropertyChangingEvent(string propertyName)
        {
            PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
        }

        #endregion
    }
}

My view model:

using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Text;

namespace TabControlError.ViewModels
{
    class MainWindowViewModel : ViewModelBase
    {
        public MainWindowViewModel()
        {
            Numbers.Add(0);
            Numbers.Add(1);
            Numbers.Add(2);
            Numbers.Add(3);
        }




        private string _text;
        public string Text
        {
            get { return _text; }
            set
            {
                if (_text != value)
                {
                    _text = value;
                    RaisePropertyChangedEvent();
                }
            }
        }



        private ObservableCollection<long> _numbers = new ObservableCollection<long>();
        public ObservableCollection<long> Numbers
        {
            get { return _numbers; }
            set
            {
                if (_numbers != value)
                {
                    _numbers = value;
                    RaisePropertyChangedEvent();
                }
            }
        }

        private long? _numbersSelectedItem;
        public long? NumbersSelectedItem
        {
            get { return _numbersSelectedItem; }
            set
            {
                if (_numbersSelectedItem != value)
                {
                    _numbersSelectedItem = value;
                    RaisePropertyChangedEvent();
                }
            }
        }

        private ObservableCollection<object> _numbersSelectedItems = new ObservableCollection<object>();
        public ObservableCollection<object> NumbersSelectedItems
        {
            get { return _numbersSelectedItems; }
            set
            {
                _numbersSelectedItems = value;
                Text = NumbersSelectedItem?.ToString();
                RaisePropertyChangedEvent();
            }
        }
    }
}

My attached property:

using System.Windows;
using System.Collections;
using System.Windows.Controls;

namespace TabControlError.DependencyProperties
{
    class DataGridSelectedItemsDependencyProperty
    {
        #region SelectedItems
        ///
        /// SelectedItems Attached Dependency Property
        ///
        public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.RegisterAttached("SelectedItems", typeof(IList),
        typeof(DataGridSelectedItemsDependencyProperty),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        new PropertyChangedCallback(OnSelectedItemsChanged)));

        public static IList GetSelectedItems(DependencyObject d)
        {
            return (IList)d.GetValue(SelectedItemsProperty);
        }

        public static void SetSelectedItems(DependencyObject d, IList value)
        {
            d.SetValue(SelectedItemsProperty, value);
        }

        private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {   
            DataGrid miDataGrid = (DataGrid)d;
            miDataGrid.SelectionChanged += DataGrid_SelectionChanged;
            miDataGrid.Unloaded += dataGrid_Unloaded;
        }

        private static void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            DataGrid miDatagrid = (DataGrid)sender;

            IList ModelSelectedItems = GetSelectedItems(miDatagrid);

            ModelSelectedItems.Clear();

            if (miDatagrid.SelectedItems != null)
            {
                foreach (var item in miDatagrid.SelectedItems)
                    ModelSelectedItems.Add(item);
            }
            SetSelectedItems(miDatagrid, ModelSelectedItems);
        }


        private static void dataGrid_Unloaded(object sender, RoutedEventArgs e)
        {   
            DataGrid miDg = sender as DataGrid;
            miDg.SelectionChanged -= DataGrid_SelectionChanged;
            miDg.Unloaded -= dataGrid_Unloaded;
        }
        #endregion
    }
}

Why does it stop working when I change the tab in the tab control?

Thanks.

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,663 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
760 questions
0 comments No comments
{count} votes

Accepted answer
  1. DaisyTian-1203 11,616 Reputation points
    2021-02-25T08:27:06.207+00:00

    I tested your code and can reproduce your error. To anlayze the error, I cut Text = NumbersSelectedItem?.ToString(); from line 73 and insert it between line 60 and line 61 for your third part code (MainWindowViewModel ) in the question, then the project worked well. From this, we can think problem comes from your custom DependencyProperty SelectedItems.

    I check your DataGridSelectedItemsDependencyProperty and found that the dataGrid_Loaded method was missing from it. I add dataGrid_Loaded in your OnSelectedItemsChanged and implement dataGrid_Loaded in the class like below shown:

    private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  
            {  
                DataGrid miDataGrid = (DataGrid)d;  
                miDataGrid.SelectionChanged += DataGrid_SelectionChanged;  
                miDataGrid.Unloaded += dataGrid_Unloaded;  
                miDataGrid.Loaded += dataGrid_Loaded; ;  
            }  
      
            private static void dataGrid_Loaded(object sender, RoutedEventArgs e)  
            {  
                DataGrid miDg = sender as DataGrid;  
                miDg.SelectionChanged += DataGrid_SelectionChanged;  
                miDg.Loaded += dataGrid_Loaded;  
            }  
    

    After doing this, the set method of NumbersSelectedItems will be called and the program can run well when the window reloads.


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful