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 aObservableCollection<TabViewModel>
. Sin enlaces paraTextBox
. Problema observado - Fila 0, columna 1: TextBox, TabItems normales, pestañas no vinculadas a
ObservableCollection<TabViewModel>
. Sin enlace paraTextBox
. No hay problemas - Fila 0, columna 2: TextBox, pestañas vinculadas a
ObservableCollection<TabViewModel>
. Sin enlaces paraTextBox
. No hay problemas - Fila 1, columna 0:
UserControl
, pestañas vinculadas aObservableCollection<TabViewModel>
. Sin enlaces paraUserControl
. Problema observado - Fila 1, columna 2:
UserControl
, pestañas vinculadas aObservableCollection<TabViewModel>
. Enlaces paraUserControl
. 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:
- Elimine la propiedad de dependencia
Text
de su control de usuario: no lo necesita Cambie su
ContentTemplate
en elTabControl
al siguiente. Esto hace que la propiedadUserControl.DataContext
se establezca en el elemento de tabulaciónDataContext
<DataTemplate> <local:UserControl1 /> </DataTemplate>
Cambie su
UserControl
al siguiente. Esto vincula la propiedadText
a la propiedadUserControl.DataContext.Text
.<TextBox Text="{Binding Text}" />
Elimine la línea
this.DataContext = this
del constructor deUserControl1
- esto obviamente reemplazará elDataContext
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