TabControl 中选项卡的 DataContextChanged 引发得太早

发布于 2024-09-25 20:40:42 字数 3396 浏览 7 评论 0原文

我有一个 TabControl 绑定到一些项目。它下面是一个按钮,我可以在其中动态添加项目。添加项目时,新项目应成为活动选项卡(与 TabControl.SelectedItem 配合使用效果良好):

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:this="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TabControl ItemsSource="{Binding Items}"
                    SelectedItem="{Binding SelectedItem, Mode=OneWay}">
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <this:UserControl1 />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
        <Button Content="Foo" Click="Button_Click"/>
    </StackPanel>
</Window>

代码隐藏:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : INotifyPropertyChanged
    {
        public ObservableCollection<Foo> Items { get; set; }
        public Foo SelectedItem { get { return Items.Last(); } }
        public event PropertyChangedEventHandler PropertyChanged;

        public MainWindow()
        {
            Items = new ObservableCollection<Foo>();
            Items.Add(new Foo {Bar = "bar"});

            InitializeComponent();
            DataContext = this;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Items.Add(new Foo {Bar = "bar"});

            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Items"));
                PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
            }
        }
    }

    public class Foo { public string Bar { get; set; } }
}

UserControl1 如下所示:

<UserControl x:Class="WpfApplication1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <TextBox/>
        <TextBox x:Name="_textBox"
             DataContextChanged="OnDataContextChanged"
             Text="{Binding Bar}" />
    </StackPanel>
</UserControl>

当用户单击时,其隐藏代码应聚焦 _textBox 并选择其所有文本在选项卡上:

using System.Windows;

namespace WpfApplication1
{
    public partial class UserControl1
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        private void OnDataContextChanged(object sender,
                                          DependencyPropertyChangedEventArgs e)
        {
            _textBox.Focus();
            _textBox.SelectAll();
        }
    }
}

我尝试通过 DataContextChanged 事件来实现这一点,但由于其不可预测性(sf http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.datacontextchanged.aspx),它并不总是有效。我还尝试使用 Loaded-event,但是在加载 DataTemplate 时只会调用一次。

因此,我认为每次 DataContext 发生更改且数据绑定引擎完成其工作时,我都需要接收 Loaded 事件。有这样的活动吗?

I have a TabControl binding to some items. Underneath it is a Button where I can add items dynamically. On adding an item, the new item should become the active Tab (works fine with TabControl.SelectedItem):

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:this="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TabControl ItemsSource="{Binding Items}"
                    SelectedItem="{Binding SelectedItem, Mode=OneWay}">
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <this:UserControl1 />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
        <Button Content="Foo" Click="Button_Click"/>
    </StackPanel>
</Window>

Code-behind:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : INotifyPropertyChanged
    {
        public ObservableCollection<Foo> Items { get; set; }
        public Foo SelectedItem { get { return Items.Last(); } }
        public event PropertyChangedEventHandler PropertyChanged;

        public MainWindow()
        {
            Items = new ObservableCollection<Foo>();
            Items.Add(new Foo {Bar = "bar"});

            InitializeComponent();
            DataContext = this;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Items.Add(new Foo {Bar = "bar"});

            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Items"));
                PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
            }
        }
    }

    public class Foo { public string Bar { get; set; } }
}

The UserControl1 looks like this:

<UserControl x:Class="WpfApplication1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <TextBox/>
        <TextBox x:Name="_textBox"
             DataContextChanged="OnDataContextChanged"
             Text="{Binding Bar}" />
    </StackPanel>
</UserControl>

And the code-behind of it should focus _textBox and selectAll its text when the user clicks on the tab:

using System.Windows;

namespace WpfApplication1
{
    public partial class UserControl1
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        private void OnDataContextChanged(object sender,
                                          DependencyPropertyChangedEventArgs e)
        {
            _textBox.Focus();
            _textBox.SelectAll();
        }
    }
}

I try to achieve that with the DataContextChanged-event, but due to its unpredictability (s.f. http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.datacontextchanged.aspx), it doesn't work all the time. I also tried it with the Loaded-event, but this will be called only once when the DataTemplate is loaded.

So, I think I need to receive the Loaded-event every time the DataContext has changed and the data-binding engine has finished its job. Is there such an event?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

意中人 2024-10-02 20:40:42

您是否想在用户添加选项卡以及用户单击不同选项卡时选择文本?

如果是这种情况,您可能需要使用两个事件处理程序来处理此问题 - 选项卡控件的选项卡更改事件 - 然后在添加新项目时在代码中设置它。

根据您的代码的 DataContext 不会改变。它被设置到主窗口,然后继承到子控件。

    public MainWindow()
    {
        Items = new ObservableCollection<Foo>();
        Items.Add(new Foo {Bar = "bar"});

        InitializeComponent();
        DataContext = this;
    }

Are you wanting to select the text when the user adds a tab AND when the user clicks on a different tab?

If this is the case you may want to to handle this with two event handlers - The tab changed event for the tab control - and then setting it in code when you add a new item.

The DataContext according to your code does not change. It is set to the main window and then inherited down to the child controls.

    public MainWindow()
    {
        Items = new ObservableCollection<Foo>();
        Items.Add(new Foo {Bar = "bar"});

        InitializeComponent();
        DataContext = this;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文