【问题标题】:WPF - Elements inside DataTemplate property issue when no binding?WPF - 没有绑定时DataTemplate属性中的元素问题?
【发布时间】:2016-12-29 17:05:47
【问题描述】:

我有以下 TabControl:

<TabControl ItemsSource="{Binding Tabs"}>
    <TabControl.ContentTemplate>
        <DataTemplate DataType="{x:Type vm:TabVM}">
            <TextBox></TextBox>
            <TextBox Text="{Binding SomeProperty}"></TextBox>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

意外的行为是第一个 TextBox 在所有 tabitems 之间共享 Text 属性,而第二个 TextBox 有效地绑定到 ViewModel 属性。

我的需要也是让第一个 TextBox 独立,即使没有绑定。

我能做什么?

** 更新 **

经过几次尝试,我决定使用 ikriv 的 TabContent.cs。 我发现的唯一问题是调用 TabControl.Items.Refresh()(即删除 tabItem 后)会导致内部缓存重置。

一个不雅但有效的解决方案可能是这样的:

public ContentManager(TabControl tabControl, Decorator border)
{
    _tabControl = tabControl;
    _border = border;
    _tabControl.SelectionChanged += (sender, args) => { UpdateSelectedTab(); };

    /* CUSTOM */
    var view = CollectionViewSource.GetDefaultView(((TabControl)_tabControl).Items);
    view.CollectionChanged += View_CollectionChanged;
}

/*
 * This fix the internal cache content when calling items->Refresh() method
 * */
private void View_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    if (e.OldItems != null)
    {
        /* Retrieve all tabitems cache and store to a temp list */
        IList<ContentControl> cachedContents = new List<ContentControl>();

        foreach (var item in _tabControl.Items)
        {
            var tabItem = _tabControl.ItemContainerGenerator.ContainerFromItem(item);

            var cachedContent = TabContent.GetInternalCachedContent(tabItem);

            cachedContents.Add(cachedContent);
        }

        /* rebuild the view */
        _tabControl.Items.Refresh();

        /* Retrieve all cached content and store to the tabitems */
        int idx = 0;

        foreach (var item in _tabControl.Items)
        {
            var tabItem = _tabControl.ItemContainerGenerator.ContainerFromItem(item);

            TabContent.SetInternalCachedContent(tabItem, cachedContents[idx++]);
        }
    }
}

【问题讨论】:

  • 试试TabControl.ItemTemplate而不是ContentTemplate
  • ItemTemplate 用于 TabItem 标头,而不是内容
  • 如果您想设置项目模板,请使用TabControl.ItemContainerStyle (&lt;Style TargetType="TabItem"&gt;...) 并为TabItemContentTemplate 属性赋予Style 一个SetterTabControlContentTemplate 属性不是您想要的。这不是很好。
  • 你可以试试这个,TabControlEx

标签: c# wpf mvvm


【解决方案1】:

您应该使用数据绑定,因为相同的 ContentTemplate 将应用于您的 ItemsSource 中的所有项目。基本上切换标签时只会刷新绑定。文本框不会重新创建也不会重置。

我能做什么?

您可以在视图中通过处理 TabControl 的 SelectionChanged 事件并自己重置 TextBox 控件来解决此问题:

private void tabs_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        TabControl tc = sender as TabControl;
        ContentPresenter cp = tc.Template.FindName("PART_SelectedContentHost", tc) as ContentPresenter;
        if(cp != null && VisualTreeHelper.GetChildrenCount(cp) > 0)
        {
            ContentPresenter cpp = VisualTreeHelper.GetChild(cp, 0) as ContentPresenter;
            if(cpp != null)
            {
                TextBox textBox = cpp.FindName("txt") as TextBox;
                if (textBox != null)
                    textBox.Text = string.Empty;
            }
        }
    }

    <TabControl x:Name="tabs" ItemsSource="{Binding Tabs}" SelectionChanged="tabs_SelectionChanged">
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ContentPresenter>
                    <ContentPresenter.Content>
                        <StackPanel>
                            <TextBox x:Name="txt"></TextBox>
                        </StackPanel>
                    </ContentPresenter.Content>
                </ContentPresenter>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>

如果您希望在切换选项卡时将文本保留在 TextBox 中,您可以使用以下文章中的附加行为并将其 IsCached 属性设置为 true:https://www.codeproject.com/articles/460989/wpf-tabcontrol-turning-off-tab-virtualization

<TabControl ItemsSource="{Binding Items}" behaviors:TabContent.IsCached="True">
    <!-- Make sure that you don't set the TabControl's ContentTemplate property but the custom one here-->
    <behaviors:TabContent.Template>
        <DataTemplate>
            <StackPanel>
                <TextBox />
            </StackPanel>
        </DataTemplate>
    </behaviors:TabContent.Template>
</TabControl>

另一种方法是修改 TabControl 的 ControlTemplate 以包含一个 ListBox,正如 MSDN 论坛上以下主题中的“gekka”所建议的那样:https://social.msdn.microsoft.com/Forums/en-US/4b71a43a-26f5-4fef-8dc5-55409262298e/using-uielements-on-datatemplate?forum=wpf

【讨论】:

  • gekka 方法是我发现的最好的方法,唯一的问题是每次删除标签时,所有 tabitem 的内容也会重置
  • 请看我编辑的答案。您应该可以使用以下文章中的解决方案:codeproject.com/articles/460989/…
  • 我也在看这个解决方案,但是当我删除一个选项卡时出现问题,因为所有其他选项卡都重置了它的非绑定内容
  • 我不明白你的意思。你能提供一个回购吗?
  • 你为什么要调用 TabControl.Items.Refresh 方法? “Tabs”源集合,即 TabControl 的 ItemsSource 属性绑定到的属性,应该是一个可以动态添加或删除项目的 ObservableCollection。然后你不需要重置 TabControl 本身。这样做不是 MVVM。
猜你喜欢
  • 1970-01-01
  • 2015-09-09
  • 2011-07-05
  • 2017-02-26
  • 2011-02-23
  • 2018-04-26
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
相关资源
最近更新 更多