Могу ли я иметь несколько экземпляров одного и того же UserControl в одном приложении? - PullRequest
3 голосов
/ 29 октября 2010

Я создаю приложение типа текстового редактора. Я могу иметь несколько редакторов, открытых через вкладки. В первой попытке я использовал простые 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 s в приложении, имеющими одинаковое содержимое.

XAML для UserControl

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

Я создал простой проект Visual Studio, размещенный @ mediafire , иллюстрирующий эту проблему. У меня такое чувство, что это как-то связано с TabViewModel s или шаблонами данных вкладок


Обновление 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, обычные элементы Tab, элементы Tab не привязаны к ObservableCollection<TabViewModel>. Нет привязки для TextBox. Нет проблем
  • Строка 0, столбец 2: TextBox, вкладки привязаны к ObservableCollection<TabViewModel>. Нет привязок для TextBox. Без проблем
  • Строка 1, столбец 0: UserControl, вкладки привязаны к ObservableCollection<TabViewModel>. Нет привязок для UserControl. Проблема наблюдается
  • Строка 1, столбец 2: UserControl, вкладки привязаны к ObservableCollection<TabViewModel>. Привязки для UserControl. Проблема наблюдается. Привязки к тексту не работают

Обновление @ mediafire

Ответы [ 2 ]

3 голосов
/ 29 октября 2010

Большое редактирование в ответ на обновления

Я могу заставить ваш пример 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 для пользовательского элемента управления.

Это привело к правильной привязке вкладок к ожидаемым значениям в загруженном образце приложения.


Оригинальный ответ

Вы можете иметь несколько экземпляров 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

.
0 голосов
/ 06 ноября 2010

Вас может заинтересовать Writer пример приложения WPF Application Framework (WAF) . В нем показано, как реализовать приложение для обработки текста с поддержкой нескольких вкладок с помощью шаблона MVVM.

...