【问题标题】:Can I have multiple instances of the same UserControl in 1 app?我可以在 1 个应用程序中拥有同一个 UserControl 的多个实例吗?
【发布时间】:2011-05-02 07:22:33
【问题描述】:

我正在创建一个文本编辑器类型应用程序。我可以通过标签打开多个编辑器。在我的第一次尝试中,我使用简单的TextBoxes 来编辑文本。一切正常。然后我创建了一个UserControl,封装了文本框+按钮来执行文本操作,例如。粗体/斜体等。我发现当我打开不同的选项卡时,它们都包含相同的内容。例如。在 Tab1 中,我输入将出现在所有选项卡中的“hello world”。即使它们位于不同的选项卡中,也没有“分离”

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:EditorTabViewModel}">
        <me:MarkdownEditor />
    </DataTemplate>
</Window.Resources>

然后我作为一个测试,尝试了一个文本框和用户控件,看看我是否有同样的问题。

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:EditorTabViewModel}">
        <StackPanel>
            <me:MarkdownEditor Text="{Binding Content}" Height="360" />
            <TextBox Text="{Binding Content}" Height="360" />
        </StackPanel>
    </DataTemplate>
</Window.Resources>

然后我发现了一些奇怪的事情。对于一个内容不应该是任何内容的新文档,我的MarkdownEditor 在其文本框中有“System.Windows.Controls.Grid”,因为它是一个网格绑定到文本。文本简单 TextBox 按预期工作。此外,应用程序中的所有UserControls 内容相同,我仍然遇到同样的问题。

UserControl 的 XAML

<UserControl x:Class="MarkdownEditMVVM.Controls.MarkdownEditor.MarkdownEditor" ...>
    <Grid>
        <ToolBar Grid.Row="0">
            <Button Command="{x:Static local:Commands.PreviewCommand}">
                <Image Source="../../Images/16/zoom.png" />
            </Button>
            <!-- more buttons -->
        </ToolBar>
        <TextBox Grid.Row="1" x:Name="txtEditor" AcceptsReturn="True" Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</UserControl>


更新

我发现这与我在标签绑定到 ObservableCollection&lt;TabViewModel&gt; 的标签中呈现用户控件的方式有关

假设我有一个 TabViewModel 甚至只是一个空类

public class TabViewModel {}

然后在我的窗口

public partial class Window1 : Window
{
    protected ObservableCollection<TabViewModel> _tabs;
    protected ICollectionView _tabsCollectionView;

    public Window1()
    {
        InitializeComponent();
        this.DataContext = this;
        _tabs = new ObservableCollection<TabViewModel>();
        _tabs.Add(new TabViewModel());
        _tabs.Add(new TabViewModel());
        _tabsCollectionView = CollectionViewSource.GetDefaultView(_tabs);
    }

    public ICollectionView Tabs
    {
        get { return _tabsCollectionView; }            
    }
}

XAML

<TabControl ItemsSource="{Binding Tabs}" IsSynchronizedWithCurrentItem="True">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <DataTemplate>
            <TextBox />
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

我创建了一个托管@mediafire 的简单Visual Studio 项目来说明这个问题。我感觉这与TabViewModels 或选项卡数据模板有关


更新 2

我通过添加另一个选项卡控件进一步测试了用户控件问题,这次没有TabViewModel

<TabControl Grid.Column="1">
    <TabItem Header="Tab 1">
        <TextBox />
    </TabItem>
    <TabItem Header="Tab 2">
        <TextBox  />
    </TabItem>
</TabControl>

一切正常。更新也发布到mediafire


更新 3

又发现了一个。这一次,我用绑定进行了测试。一切正常...

<TabControl Grid.Column="2" ItemsSource="{Binding Tabs}" IsSynchronizedWithCurrentItem="True">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding TabTitle}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <DataTemplate>
            <TextBox Text="{Binding Text}" />
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

更新也发布@mediafire


更新 4

好的,现在我做了一套更完整的测试

  • 第 0 行,第 0 列:TextBox,标签绑定到ObservableCollection&lt;TabViewModel&gt;TextBox 没有绑定。发现问题
  • 第 0 行,第 1 列:文本框、普通 TabItems、未绑定到 ObservableCollection&lt;TabViewModel&gt; 的选项卡。 TextBox 没有绑定。没问题
  • 第 0 行,第 2 列:文本框,绑定到 ObservableCollection&lt;TabViewModel&gt; 的选项卡。 TextBox 没有绑定。没问题
  • 第 1 行,第 0 列:UserControl,标签绑定到 ObservableCollection&lt;TabViewModel&gt;UserControl 没有绑定。发现问题
  • 第 1 行,第 2 列:UserControl,标签绑定到 ObservableCollection&lt;TabViewModel&gt;UserControl 的绑定。观察到问题。文本绑定不起作用

更新@mediafire

【问题讨论】:

    标签: c# wpf user-controls mvvm tabcontrol


    【解决方案1】:

    大编辑以响应更新

    我可以通过以下步骤让您的 mediafire 示例正常工作:

    1. 从您的用户控件中删除依赖属性 Text - 您不需要它
    2. TabControl 上的ContentTemplate 更改为以下内容。这会导致UserControl.DataContext 属性设置为标签项DataContext

       <DataTemplate>
            <local:UserControl1 />
       </DataTemplate>
      
    3. 将您的UserControl 更改为以下内容。这会将Text 属性绑定到UserControl.DataContext.Text 属性。

      <TextBox Text="{Binding Text}" />
      
    4. UserControl1 的构造函数中删除行this.DataContext = this - 这显然会替换用户控件的DataContext

    这导致选项卡与您上传的示例应用程序中的预期值正确绑定


    原答案

    您可以拥有多个 UserControl 实例 - 这不是您的问题。

    您看到“System.Windows.Controls.Grid”文本的原因是因为在您的UserControl 中,您将Text 属性绑定到this.DataContext.Text 而不是this.Text - 属性 你的UserControl

    我认为您想要做的是将用户控件中的 TextBox 绑定更改为:

    <TextBox Grid.Row="1" x:Name="txtEditor" AcceptsReturn="True"
    Text="{Binding Path=Text,
            UpdateSourceTrigger=PropertyChanged,
            RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type me:MarkDownEditor}}}" />
    

    注意:这依赖于 me 命名空间被设置为指向您的 MarkDownEditor 所在的位置

    【讨论】:

    • 嗯,我试过了,得到了 StackOverflow 异常。我仍然没有真正理解数据上下文问题......也许是因为我也从未使用过RelativeSource
    • 那是我的错误 - 我绑定到 TextBlock 而不是 MarkDownEditor 上的属性:s - 已编辑帖子以纠正问题
    • 嗯,这很奇怪我仍然遇到同样的网格问题......我还尝试创建一个自定义控件,在干净的应用程序中使用更多准系统,我没有这样的问题......必须在某处做错了什么,你对这些问题有什么建议吗?随着我的发展,我以某种方式引入了奇怪的错误,但它们单独工作正常。 IE。当我只有 1 个用户控件时,它工作正常。我应该重写所有内容,然后一次复制并粘贴一个功能吗?
    • 不幸的是,在 WPF 应用程序中调试行为通常有点棘手,因为您通常无法设置断点。如果我得到你的那种行为,我通常会将属性的绑定更改为尽可能简单的东西(例如{Binding})并查看生成的值,然后从那里开始工作。你也可以在Binding 上设置一个IValueConverter,如果你真的很挣扎,你可以在其中指定一个断点...
    • 查看更新,我不认为问题出在绑定上,我删除了所有绑定,但仍然有同样的问题。
    【解决方案2】:

    您可能对 WPF Application Framework (WAF)Writer 示例应用程序感兴趣。它展示了如何通过应用 MVVM 模式来实现具有多个选项卡支持的文本处理应用程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-13
      • 1970-01-01
      • 2012-05-25
      • 1970-01-01
      • 2018-04-03
      • 2023-01-13
      • 1970-01-01
      相关资源
      最近更新 更多