我可以在一个应用程序中拥有同一UserControl的多个实例吗?

时间:2010-10-29 08:42:45

标签: c# wpf user-controls mvvm tabcontrol

我正在创建一个文本编辑器类型应用程序。我可以通过标签打开多个编辑器。在我的第一次尝试中,我使用简单的TextBox es来编辑文本。一切正常。然后我创建了一个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”,因为Grid绑定到文本。文本简单TextBox按预期工作。此外,我在应用中具有相同内容的所有UserControl仍存在同样的问题。

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

的标签中呈现的用户控件的方式有关

假设我有 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项目,说明了这个问题。我觉得它与TabViewModel或标签数据模板

有关


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

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

alt text

  • 第0行,第0列:TextBox,标签绑定到ObservableCollection<TabViewModel>。没有TextBox的绑定。观察到的问题
  • 第0行,第1列:TextBox,Normal TabItems,未绑定到ObservableCollection<TabViewModel>的选项卡。没有绑定TextBox。没问题
  • 第0行,第2列:TextBox,标签绑定到ObservableCollection<TabViewModel>。没有TextBox的绑定。没问题
  • 第1行,第0列:UserControl,标签绑定到ObservableCollection<TabViewModel>。没有UserControl的绑定。观察到的问题
  • 第1行,第2列:UserControl,标签绑定到ObservableCollection<TabViewModel>UserControl的绑定。观察到问题。文本绑定无法正常工作

更新@ mediafire

2 个答案:

答案 0 :(得分:3)

大编辑以响应更新

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

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

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

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

  5. 这导致标签与您上传的示例应用中的预期值正确绑定


    原始答案

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

    您看到“System.Windows.Controls.Grid”文本的原因是因为在UserControl中您将Text属性绑定到this.DataContext.Text而不是this.Text } - of 你的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所在的位置

答案 1 :(得分:0)

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