当我更改选项卡并返回时,所选项目的附加 属性 停止工作

The attached property of the selected items stops working when I change the tab and back

我有一个视图和一个视图模型。我有一个 DataGrid,当我 select 一行时,TextBox 显示该行的值。这只是为了显示 SelectedItems 是否被触发。

它工作正常,但如果我切换到另一个选项卡并返回,它就会停止工作。

我的看法:

<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>

我的视图模型库:

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>
        
        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>
        
        public virtual void RaisePropertyChangingEvent(string propertyName)
        {
            PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
        }

        #endregion
    }
}

我的视图模型:

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();
            }
        }
    }
}

我的附件属性:

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;

            //Esta variable tiene la colección del view model, o la propiedad que hace el binding al dependency property del datagrid.
            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
    }
}

为什么在选项卡控件中更改选项卡时它停止工作?

WPF 选项卡控件只有一个内容展示器。当您切换选项卡时,数据网格将被卸载并调用您的 Unloaded 事件处理程序,从而删除 SelectionChanged 处理程序。当你切换回去时,数据网格再次加载,但 SelectedItems 值没有改变,所以你永远不会添加 SelectionChanged 处理程序,这就是为什么它永远不会再次调用并且项目不同步的原因.

您可以将处理程序添加到数据网格的 Loaded 事件,以重新附加同步所选项目的 SelectionChanged 处理程序。例如,像这样的东西应该可以工作:

public class DataGridSelectedItemsDependencyProperty
{
   // ...your other code.

   private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   {
      DataGrid miDataGrid = (DataGrid)d;

      if (e.OldValue != null)
      {
         miDataGrid.SelectionChanged -= DataGrid_SelectionChanged;
         miDataGrid.Loaded -= dataGrid_Loaded;
         miDataGrid.Unloaded -= dataGrid_Unloaded;
      }

      if (e.NewValue != null)
      {
         miDataGrid.SelectionChanged += DataGrid_SelectionChanged;
         miDataGrid.Loaded += dataGrid_Loaded;
         miDataGrid.Unloaded += dataGrid_Unloaded;
      }
   }

   private static void dataGrid_Loaded(object sender, RoutedEventArgs e)
   {
      DataGrid miDataGrid = (DataGrid)sender;
      miDataGrid.SelectionChanged += DataGrid_SelectionChanged;
   }

   // ...your other code.
}