WPF UserControlA with List<UserControlB>Property - c#

i want to have a user UserControl derived class with a List of objects of another UserControl derived class which i can use in xaml.
<UserControlA>
<UserControlA.Items>
<UserControlB Width=10 Height=10 />
<UserControlB Width=10 Height=10 />
<UserControlB Width=10 Height=10 />
<UserControlA.Items>
<UserControlA>
I don't know how to implement the Items Property of UserControlA to allow this. I already tried to implemet it as a dependency property of type Items : List<UserControlB> but this does copy the whole xaml from USerControlB into the UserControlA.Items section.
Thanks for any Help

It really looks like you are "over-doing" it. You may just want to Style or Template an ItemsControl or ListBox and DataTemplate the Items within.
Here's some code:
<ListBox>
<ListBox.Template>
<ControlTemplate>
<!--The control functionality of UserControlA-->
<ItemsPresenter/>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl/> <!--UserControlB-->
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Related

UWP Inherit from Control

For example I have a UserControl like this:
<UserControl x:Class="SMPlayer.ScrollingTextBlock">
<ScrollViewer
x:Name="TextScrollViewer"
HorizontalScrollBarVisibility="Hidden"
PointerEntered="TextScrollViewer_PointerEntered"
VerticalScrollBarVisibility="Disabled">
<StackPanel>
<TextBlock x:Name="NormalTextBlock" />
<TextBlock x:Name="PointerOverTextBlock" Visibility="Collapsed" />
</StackPanel>
</ScrollViewer>
</UserControl>
I want this UserControl still to be treated as a normal TextBlock. For example <ScrollingTextBlock Text="Something"/>. It is just a TextBlock with more functionalities, or in other words, another control that inherits from TextBlock. Because there are a lot of properties, I don't want to do this manually by adding DependencyProperty and do things like public string Text { get; set; }. It is just too much work.
How can I achieve that? I think this question might have been asked but I am not sure how to properly paraphrase it.
If you want to implement <ScrollingTextBlock Text="Something"/> in UserControl, you still need to add DependencyProperty to achieve it.
If you want your control to "be treated as a normal TextBlock", then you don't have any other choice than inheriting from TextBlock. This is what inheritance is for.
Otherwise you indeed have to add properties to your UserControl and bind them by yourself, even though this is a lot of work this is due to the poor flexibility of the UserControl. You cannot have a Text property on an object unless it inherits from a TextBlock or you add it yourself.
Alternatively you can use templating to re-template a ContentControl like this:
public class ScrollingContent : ContentControl { }
<Window.Resources>
<Style TargetType="local:ScrollingContent">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ScrollingContent">
<ScrollViewer
x:Name="TextScrollViewer"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Disabled">
<StackPanel>
<TextBlock x:Name="NormalTextBlock" />
<ContentPresenter></ContentPresenter>
</StackPanel>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<local:ScrollingContent>
<TextBlock Text="Whatever control I want" Foreground="Red"></TextBlock>
</local:ScrollingContent>
</Grid>
But then again, your control is not really a TextBlock.

TabControl - Display N TabItems depending on List<List<T>> dimension [duplicate]

If I have a class called: GuiObject, and that class has a list of GuiObjects called: "GuiObjects".
Now say my window has a list of GuiObjects, which I use in the .xaml file to dataBind to:
<StackPanel>
<ItemsControl ItemsSource="{Binding TopObjectList}" DataTemplateSelector="{DynamicResource templateSelector"/>
</StackPanel>
I can make a datatemplate for every type of FrameworkElement I want to generate, but I'm having trouble with the TabControl. I can create a datatemplate for the tabControl like so:
<DataTemplate x:key="TabControlTemplate" DataTemplateSelector="{DynamicResource templateSelector" >
<TabControl ItemsSource="{Binding GuiObjects}" />
</DataTemplate>
And the result is a tab control that has each of the proper pages present, but without the contents of the individual TabItems. Fair enough, I'll just make a DataTemplate for the TabItems. For each TabItem, I'd like to put the contents of GuiObjects into a stackpanel.
<DataTemplate x:key="TabItemTemplate" DataTemplateSelector="{Resource templateSelector">
<TabItem Header = {Binding Title}>
<StackPanel>
<ItemsControl ItemsSource="{Binding GuiObjects}" DataTemplateSelector="{DynamicResource templateSelector"/>
</StackPanel>
</TabItem>
</DataTemplate>
The problem here is that the TabItemTemplate never gets called. I've tried solutions that involve setting the ItemContainerStyle within the TabControlTemplate, but then I've got the problem of hierarchy. If I bind "GuiObjects" inside the content of the TabItem, I'm binding the list of tabItems, instead of the list that's within each TabItem. (I want to do the second one). Here's an example:
<DataTemplate x:key="TabControlTemplate" DataTemplateSelector="{DynamicResource templateSelector" >
<TabControl ItemsSource="{Binding GuiObjects}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Title}"/>
<Setter Property="Content" Value="<StackPanel><ItemsControl ItemsSource="{Binding GuiObjects}" DataTemplateSelector="{DynamicResource templateSelector"/></StackPanel>"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</DataTemplate>
Again, this solution has the levels problem: When I say: {Binding GuiObjets} I'm referring to the list of TabItems, instead of to the list of FrameworkElements within each TabItem.
The solution is either to stick with separate DataTemplates for both the TabControl and the TabItem, and just fix it so that the DataTemplateSelector actually works for the TabItems (no idea how to do this). Or to go with the ItemContainerStyle, and somehow tell it to go down one level when binding GuiObjects. Anyone know how to do this?
To provide a template for the contents of the pages of a TabControl, use the following properties:
ContentTemplate
ContentTemplateSelector
The ItemTemplate/ItemTemplateSelector properties of a TabControl are used to define what the tab headers look like.

Assigning multiple views to one viewmodel WPF C#

I have an application where I assign each of the views datacontext through the datatemplate in xaml.
The problem is I now have a viewmodel implemented as a singleton and need to have two views using it.
Is there some way to set multiple views in the one datatemplate?
Something like below which I know does not work, I am just using this as an example of what I mean:
<DataTemplate DataType="{x:Type viewModel:ThisViewModel}">
<view:ViewOne />
<view:ViewTwo />
</DataTemplate>
Thanks
I'm not sure if I understand you entirely, but it sounds like you need to assign a Key to your DataTemplates
<DataTemplate x:Key="DataTemplate1" DataType="{x:Type viewModel:ThisViewModel}">
<view:ViewOne />
</DataTemplate>
<DataTemplate x:Key="DataTemplate2" DataType="{x:Type viewModel:ThisViewModel}">
<view:ViewTwo />
</DataTemplate>
Then from your regular XAML, you would specify what template you want to use for each area via it's key, like this:
<ContentControl Content="{Binding MyViewModel}"
ContentTemplate="{DynamicResource DataTemplate1}" />
<ItemsControl ItemsSource="{Binding MyViewModels}"
ItemTemplate="{DynamicResource DataTemplate2}" />
If I misunderstood and you actually want one data template containing two Views, there's no problem with that. DataTemplates can have as many elements as you want, however they can only have one main child element, so make that element a panel that is used to tell WPF how to arrange the two views.
<DataTemplate x:Key="DataTemplate1" DataType="{x:Type viewModel:ThisViewModel}">
<StackPanel>
<view:ViewOne />
<view:ViewTwo />
</StackPanel>
</DataTemplate>
Yes its possible to add two Views to a DataTemplate like below,
<DataTemplate x:Key="KeyName" DataType="{x:Type viewModel:ThisViewModel}">
<Grid>
<view:ViewOne />
<view:ViewTwo />
</Grid>
</DataTemplate>
DataTemplate can have more than one view by adding any kind of Panel as a parent Control, like Grid, StackPanel, WrapPanel etc all based on how you want to display it on the View.

ItemTemplate DesignTime hints for custom control

I would like to create custom control with ItemsSource, which ItemTemplate for these items.
I have made it working, but one thing is left:
I would like to have DesignTime helper for binding within DataTemplate. Right now I can bind properties from Collection object, but there's no hints in XAML like with other bindings.
Of course I can do something like this:
<DataTemplate>
<StackPanel d:DataContext="{d:DesignInstance models:User}">
<Label Content="{Binding FirstName}" />
<Label Content="{Binding LastName}" />
</StackPanel>
</DataTemplate>
But I would like to avoid DesignTime instances entered manually.
Is there a way to do this?
<DataTemplate DataType={x:Type User}>
By telling the DataTemplate the type that it represents; intellisense will give you DesignTime hints as to the properties available for Binding expressions

Silverlight - Binding with ObservableCollections

This is no doubt a newbish question, but I have looked for an answer to no avail. My setup is simple: I have a ListBox control defined in XAML and an ObservableCollection<MyClass> in the same class. I am binding the ObservableCollection<MyClass> to the ListBox.
Within the hierarchy of this ListBox in XAML, I want to bind to a given MyClass object, not to a child property of the MyClass object.
To clarify, I have XAML that looks like the following (I bind the ObservableCollection in code):
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<MyControls:SpecialControl MyClassObj="{Binding !!!}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Surely there is a way to get at the object of an ObservableCollection rather than being forced to bind to one of its child properties.
You do not have to specify a Path if you want to use the bound object itself:
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<MyControls:SpecialControl MyClassObj="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
BTW: Instead of your custom property, you can use the DataContext property of your control to bind the control to the object:
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<MyControls:SpecialControl DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As well as specifying the binding path in your XAML you have to bind your collection to the ListBox.
C#
ObservableCollection<MyClass> myCollection = new ObservableCollection<MyClass>();
MyListBox.DataContext = myCollection;
The XAML you have used won't be particularly useful unless you have overriden the ToString method on MyClass. Even though you say you're not are you sure it's not a property of MyClass that you want to bind to? I can't see why you'd want to bind directly to a collection object.
XAML
<ListBox x:Name="MyListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<MyControls:SpecialControl MyClassObj="{Binding Path=MyClassProperty}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Categories