c# wpf user-controls mvvm tabcontrol

c# - ¿Puedo tener varias instancias del mismo UserControl en 1 aplicación?



wpf user-controls (2)

Es posible que le interese la aplicación de ejemplo Writer del WPF Application Framework (WAF) . Muestra cómo implementar una aplicación de procesamiento de texto con soporte de múltiples pestañas mediante la aplicación del patrón MVVM.

Estoy creando una aplicación de tipo Editor de texto. Puedo tener varios editores abiertos a través de pestañas. En mi primer intento, utilicé TextBox simple para editar texto. Todo funcionó bien Luego creé un UserControl encapsulando los botones del cuadro de texto + para realizar la manipulación del texto, por ejemplo. negrita / cursiva, etc. Descubrí que cuando abro diferentes pestañas, todas contienen el mismo contenido. p.ej. En Tab1 ingreso "hello world" que aparecerá en todas las pestañas. No hay "separación" a pesar de que están en diferentes pestañas

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

Luego, como prueba, probé un cuadro de texto y el control de usuario para ver si tengo el mismo problema.

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

Luego descubrí algunas cosas extrañas. Con un nuevo documento, donde el contenido no debería ser nada, mi MarkdownEditor tenía "System.Windows.Controls.Grid" en su cuadro de texto, ya que una Grilla estaba ligada al texto. Text simple TextBox funciona como se esperaba. También tengo el mismo problema con todos los UserControl s en la aplicación que tiene el mismo contenido.

El XAML para el 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>


Actualizar

Descubrí que esto tiene algo que ver con la forma en que los controles de usuario se representan en las pestañas donde las pestañas están vinculadas a ObservableCollection<TabViewModel>

Supongamos que tengo un TabViewModel incluso solo una clase vacía

public class TabViewModel {}

Entonces en mi ventana

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>

He creado un proyecto de Visual Studio simple alojado @ mediafire que ilustra este problema. Tengo la sensación de que tiene algo que ver con TabViewModel o las plantillas de datos de tabulación


Actualización 2

TabViewModel más el problema de control del usuario agregando otro control de pestañas, esta vez sin el TabViewModel

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

Todo funcionó bien. actualización también publicada en mediafire


Actualización 3

Hizo otro hallazgo. Esta vez, probé con un enlace. las cosas funcionaron bien ...

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

Actualización también publicada @ mediafire


Actualización 4

Ok, ahora hice un conjunto más completo de pruebas

  • Fila 0, columna 0: TextBox , pestañas vinculadas a ObservableCollection<TabViewModel> . Sin enlaces para TextBox . Problema observado
  • Fila 0, columna 1: TextBox, TabItems normales, pestañas no vinculadas a ObservableCollection<TabViewModel> . Sin enlace para TextBox . No hay problemas
  • Fila 0, columna 2: TextBox, pestañas vinculadas a ObservableCollection<TabViewModel> . Sin enlaces para TextBox . No hay problemas
  • Fila 1, columna 0: UserControl , pestañas vinculadas a ObservableCollection<TabViewModel> . Sin enlaces para UserControl . Problema observado
  • Fila 1, columna 2: UserControl , pestañas vinculadas a ObservableCollection<TabViewModel> . Enlaces para UserControl . Problema observado. Las uniones de texto no funcionan

Actualizar @ mediafire


Big Edit en respuesta a las actualizaciones

Puedo hacer que tu ejemplo de mediafire funcione correctamente siguiendo estos pasos:

  1. Elimine la propiedad de dependencia Text de su control de usuario: no lo necesita
  2. Cambie su ContentTemplate en el TabControl al siguiente. Esto hace que la propiedad UserControl.DataContext se establezca en el elemento de tabulación DataContext

    <DataTemplate> <local:UserControl1 /> </DataTemplate>

  3. Cambie su UserControl al siguiente. Esto vincula la propiedad Text a la propiedad UserControl.DataContext.Text .

    <TextBox Text="{Binding Text}" />

  4. Elimine la línea this.DataContext = this del constructor de UserControl1 - esto obviamente reemplazará el DataContext para el control del usuario.

Esto causó que las pestañas se vinculen correctamente con los valores esperados en la aplicación de muestra que cargó

Respuesta original

Puede tener varias instancias de UserControl : ese no es su problema aquí.

La razón por la que está viendo el texto "System.Windows.Controls.Grid" es porque en su UserControl está vinculando la propiedad Text a this.DataContext.Text lugar de this.Text - la propiedad de su UserControl .

Creo que lo que quieres hacer es cambiar el enlace de TextBox en tu control de usuario a:

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

Nota: esto depende de que el espacio de nombres me esté configurado para señalar donde esté ubicado su MarkDownEditor