当我更改选项卡时,SelectedItems 附加属性何时停止工作?

Hui Liu-MSFT 48,681 信誉分 Microsoft 外部员工
2024-05-30T06:26:29.4066667+00:00

我有一个视图和一个视图模型。我有一个数据网格,当我选择一行时,文本框显示该行的值。这只是为了显示是否触发了 selectedItems。

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

我正在使用 Net 5。

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

我的ViewModelBase:

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

我的ViewModel:

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

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

为什么当我更改选项卡控件中的选项卡时,它停止工作?

谢谢。

Note:此问题总结整理于:When the SelectedItems attached property stops to work when I change the tab?

开发人员技术 | Windows Presentation Foundation
0 个注释 无注释
{count} 票

接受的答案
  1. 匿名
    2024-05-30T07:37:20.9533333+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;  
            }  
    

    完成此操作后,将调用 NumbersSelectedItems 的 set 方法,并且当窗口重新加载时程序可以正常运行。


    如果回复有帮助,请点击“接受答案”并点赞。

    注意:如果您想接收此线程的相关电子邮件通知,请按照我们文档中的步骤启用电子邮件通知。

    0 个注释 无注释

0 个其他答案

排序依据: 非常有帮助

你的答案

问题作者可以将答案标记为“接受的答案”,这有助于用户了解已解决作者问题的答案。