WPF staticresource references to Logical Resources in DataTemplates not resolving at runtime - wpf

Have I missed something in the step up from .net 3.5 to .net 4 because I'm seeing seemingly buggy behaviour that seems contrary to the goal of the system.
I am trying to drum up a simple MVVM library for work using a few examples. I am consuming it within a Twitter client application for some additional learning and have hit a big stumbling block.
The scenario is this. My root ViewModel (TwitterClientViewModel) object is given an instance of a DialogViewModel object for display. The DialogViewModel is added to a collection and a bool HasDialogs is set to true. PropertyChanged events are invoked for the collection and the flag if necessary. This part works fabulously.
The view for TwitterClientViewModel is called TwitterClientTemplate and makes Visible an overlay for DialogViewTemplate (DialogViewModel's view) hosting. The hosting ContentControl's template references DialogViewTemplate with a DynamicResource extension. This displays great in the designer and at runtime.
This is where things get strange. The 'body' of DialogViewTemplate hosts dialog content with a further content control bound to DialogViewModel.Content (type object). The hope was that with use of a TemplateSelector (of which I wrote a nice declarative one, but have commented out for testing purposes) I could display both text and interactive elements. For example, requesting details from the user when authenticating a Twitter account. In this case, a PIN number.
At this point I have a two nested contentcontrols for the dialog implementation. For testing purposes, the contentcontrol in the body of DialogViewTemplate uses a staticresource extension to retrieve EnterPINDialogTemplate (view for EnterPINDialogViewModel). Both EnterPINDialogTemplate and DialogViewTemplate are in the same file (the former is defined first of course) although originally they were separate.
At runtime the staticresource extension throws a XamlParseException with the message;
'Provide value on 'System.Windows.Markup.StaticResourceHolder' threw an exception.'
and an inner exception message;
'Cannot find resource named 'EnterPINDialogTemplate'. Resource names are case sensitive'
Using a dynamicresource returns null and displays the Fullname of the EnterPINDialogViewModel type in the contentcontrol - as expected when the resource is not resolved. Breaking into my custom TemplateSelector as calling FrameWorkElement.FindResource() throws a similar exception (TryFindResource returns null).
My first thought was that the logical tree is split when the datatemplates are constructed and I remembered an issue in that area from an earlier project. I tried using the MergeDictionaries property of ResourceDictionary to make the resource dictionaries avaliable from within the DataTemplate but the designer did not like that one bit, and the error is described here:
http://connect.microsoft.com/VisualStudio/feedback/details/498844/wpf-designer-throws-invalidcastexception
Scratch that idea. I have tried merging the dictionaries at Application, Window and TwitterClientTemplate levels but have had no luck.
Below are the xaml files.
DialogTemplates.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:EpicTweet.ViewModel"
xmlns:ET="clr-namespace:EpicTweet"
xmlns:T="clr-namespace:EpicTweet.Tools"
xmlns:MV="clr-namespace:MVVM;assembly=MVVM"
xmlns:Loc="clr-namespace:EpicTweet.Localization"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
<DataTemplate DataType="VM:EnterPINDialogViewModel" x:Key="EnterPINDialogTemplate">
<Grid d:DesignWidth="453.89" d:DesignHeight="78.92" Loc:ResXManagerProperty.ResourceManager="{x:Static ET:Language.ResourceManager}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="{Loc:ResxExtension ResourceName=String_PIN, FallbackValue='<PIN>'}"/>
<TextBox Grid.Column="1"/>
<TextBlock Grid.Row="1" Grid.RowSpan="2"></TextBlock>
</Grid>
</DataTemplate>
<DataTemplate x:Key="DialogViewTemplate" DataType="MV:DialogViewModel">
<Border BorderBrush="Black" BorderThickness="1">
<Grid d:DesignWidth="277.419" d:DesignHeight="74.96" Background="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" Height="Auto" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border d:LayoutOverrides="Width, Height" BorderThickness="0,0,0,1" BorderBrush="Black">
<Label Content="{Binding DisplayName, FallbackValue=Header}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
</Border>
<ContentControl Content="{Binding Content, FallbackValue=Body}" ContentTemplate="{StaticResource EnterPINDialogTemplate}" HorizontalAlignment="Stretch" d:LayoutOverrides="Height" Grid.Row="1" Margin="5">
<!--<ContentControl.ContentTemplateSelector>
<T:TypeTemplateSelector>
<T:TemplateTypeRelationship Type="{x:Type VM:EnterPINDialogViewModel}" ResourceKey="EnterPINDialogTemplate"/>
</T:TypeTemplateSelector>
</ContentControl.ContentTemplateSelector>-->
</ContentControl>
<ItemsControl Grid.Row="2" Margin="10"
ItemsSource="{Binding Commands, Mode=OneTime, FallbackValue={x:Static VM:TwitterClientViewModel.DEFAULT_DIALOG_COMMANDS}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Content="{Binding DisplayName, FallbackValue=CommandName, Mode=OneWay}"
Command="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Border>
</DataTemplate>
TwitterClientDataTemplate.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:EpicTweet.ViewModel"
xmlns:ET="clr-namespace:EpicTweet"
xmlns:MV="clr-namespace:MVVM;assembly=MVVM"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DialogTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<DataTemplate x:Key="TwitterClientTemplate" DataType="MV:TwitterClientViewModel">
<ScrollViewer d:DesignWidth="285.083" d:DesignHeight="119.96">
<Grid>
<StackPanel d:LayoutOverrides="Width, Height">
<StackPanel Orientation="Horizontal">
<Button Command="{Binding AddAccountCommand.Command}" Content="{Binding AddAccountCommand.DisplayName, FallbackValue=<Add Account>}"/>
</StackPanel>
<ContentControl/>
</StackPanel>
<Border BorderThickness="1" Background="#80000000" Visibility="{Binding HasDialogs, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed, Mode=OneWay}">
<Grid VerticalAlignment="Stretch" MinWidth="50" MaxWidth="200">
<ContentControl Content="{Binding Dialogs[0], Mode=OneWay}" ContentTemplate="{DynamicResource DialogViewTemplate}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
</Grid>
</ScrollViewer>
</DataTemplate>
Help me stackoverflow, you're my only hope!
EDIT: Did some further work on this issue. If both templates are in the same file dynamicresource and staticresource extensions both resolve the resource without issue. If they are in separate files, the resource will not resolve regardless of how I merge the dictionaries; each extension returns null.
Obviously the solution is to throw both resources into the same dictionary but as far as I'm concerned this is a hack and is not intended behaviour of the logical resource lookup system. I am not a happy bunny right now. This seems pretty undocumented...

If ever there was a pratt, it is me. After 4 hours on a Friday night trying to solve this one I have cracked it, no thanks to what I can only call flaky error reporting.
Here is the buzz.
<DataTemplate x:Key="TwitterClientTemplate" DataType="MV:TwitterClientViewModel">
should be
<DataTemplate x:Key="TwitterClientTemplate" DataType="{x:Type MV:TwitterClientViewModel}">
And bam, it works.
My big gripe remains however. Why does the incorrect syntax work in the designer but not at runtime? My guess is because runtime optimization just doesn't bother to populate a dictionary with poorly authored xaml but it would be nice to get a warning that it is wrong.

Related

WPF borderless form using WindowGlows to create a dropshadow

So I found this while I was searching for ways to get borderless wpf forms to drop a shadow. It creates a drop shadow like that of visual studio or microsoft office. After downloading from the mentioned site, I've referenced the WindowGlows.dll file in my project and copied this code from the example on the sight.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WindowGlows="http://GlowWindow.codeplex.com/"
x:Class="WindowGlowsTestApp.MainWindow"
Title="MainWindow"
Height="350"
Width="525"
WindowGlows:GlowManager.EnableGlow="True"
WindowGlows:GlowManager.ActiveGlowBrush="CornflowerBlue"
WindowGlows:GlowManager.InactiveGlowBrush="LightGray">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0"
CornerRadius="0"
CaptionHeight="36"
ResizeBorderThickness="0" />
</WindowChrome.WindowChrome>
<Border BorderThickness="1"
BorderBrush="{Binding Path=(WindowGlows:GlowManager.ActiveGlowBrush),RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="36" />
<RowDefinition />
<RowDefinition Height="24" />
</Grid.RowDefinitions>
<Rectangle Fill="{Binding Path=(WindowGlows:GlowManager.ActiveGlowBrush),RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
Margin="-1,11,-1,0"
StrokeThickness="0"
ClipToBounds="True" />
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding Title, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"
Foreground="{Binding Path=(WindowGlows:GlowManager.InactiveGlowBrush),RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
Margin="0,11,0,0" />
<Rectangle Grid.Row="2"
Fill="{Binding Path=(WindowGlows:GlowManager.ActiveGlowBrush),RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
Margin="-1,0,-1,-1"
StrokeThickness="0"
ClipToBounds="True" />
</Grid>
</Border>
When I click start, the form drops a fantastic shadow and I can put this to great use but I can't get rid of the errors, which tell me
Error 1 The name "GlowManager" does not exist in the namespace
I get 6 more errors about glow manager but nothing else, how do I correct the namespace?
After reading this link I copied the entire project straight into the root of my C drive and opened it from there, it works absolutely fine now. Looks like it's a visual studio bug if anything.
That namespace doesn't look right to me.
Assuming you have availed reference in your project to the doll, the easiest way to get these right is to use blend, from assets tab drop in a object from that DSL and it will do the rest. visual studio is a little less helpful.
Without seeing exactly what you've got, the best I can offer is change the namespace tag to something of this form...
Xmlns:windowchrome="clr-namespace:<namespace of targeted objects>,assembly=<assembly name as seen in references folder>"
msdn includes some more details, http://msdn.microsoft.com/en-gb/library/bb514546%28v=vs.90%29.aspx

Showing or hiding a control in WPF template based on bindings

I am new to WPF binding/templating. I have some basic questions about a templated TabControl I have as below :
<TabControl x:Name="tcTabs" ItemsSource="{Binding Rooms, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Margin="5" BorderThickness="1" IsSynchronizedWithCurrentItem="True">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Name}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="130"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="22"/>
</Grid.RowDefinitions>
<ListBox Grid.Row="0" Grid.Column="0" BorderThickness="0" ItemsSource="{Binding Messages}" DisplayMemberPath="Raw" />
<ListBox Grid.Row="0" Grid.Column="1" BorderThickness="1,0,0,0" BorderBrush="#FFBBBBBB" ItemsSource="{Binding Users}" DisplayMemberPath="Nick" />
<TextBox Grid.Row="1" Grid.ColumnSpan="2" BorderThickness="0,1,0,0" BorderBrush="#FFBBBBBB" Height="22" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
The TabControl contains in each tab 2 list boxes and a textbox. One of the listboxes contains user names is is not necessary all the time.
There are 3 kinds of tabs, Server tabs, room tabs and private tabs. In private and server tabs the user list should not exist or be hidden.
I have an enum on the bound room object :
public enum IRCRoomType
{
Server,
Channel,
Private
}
How do I automatically hide the user list based on the enum, I have seen samples of 2 approaches, the binding on visibility with a converter or a trigger. Which is the better approach and are there any more?
When there are no tabs, and the first tab is created it is not automatically selected, how do I select it?
Is there a way of impacting the item styles inside the listboxes depending on tab type? How would I acheive this?
I am just looking for links/hints and not for actual solutions, but if you can give code then that would be a bonus!
It depends on how complicated code. If it's simple I rather use Trigger (you have everything which belows to UI in XAML), but if code is much more complicated consider using Converters (It's actually simpler to use it)
Bind to SelectedIndex of List and set it to 0?
Yes, of course, you can use ContentControl with DataTemplate (Or just DataTemplate in some cases) Some code where I use it:
<ListBox>
<ListBox.Resources>
<DataTemplate DataType="{x:Type your_namespace:your_type}">
... your code ...
</DataTemplate>
<DataTemplate DataType="{x:Type system:String}">
... your code ...
</DataTemplate>
</ListBox.Resources>
</ListBox>
Code you posted is actually a new Template, but you've changed the Style. Please consider override some Template.
Best regards

TabControl DataTemplate Instance Creation Issues

I have a WPF issue that I don't understand - can anyone help?
The WPF below is used as the ContentTemplate for a standard TabControl and resides within a ResourceDictionary. MyElementItemsControl is a simple derivative of ItemsControl and MyDesignCanvas is a simple derivative of Canvas.
<DataTemplate x:Key="TabContent" x:Shared="False">
<Grid>
<Grid Grid.RowSpan="2">
<ScrollViewer x:Name="contentScrollViewer" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" >
<Grid>
<View:MyElementItemsControl BorderBrush="Transparent" x:Name="schedulePanel" ItemsSource="{Binding Path=Elements}" Background="White">
<View:MyElementItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<View:MyDesignCanvas Height="1000" Width="1000" HorizontalAlignment="Left" VerticalAlignment="Top"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
Background="Transparent">
</View:MyDesignCanvas>
</ItemsPanelTemplate>
</View:MyElementItemsControl.ItemsPanel>
</View:MyElementItemsControl>
<Grid.LayoutTransform>
<TransformGroup>
<ScaleTransform>
<ScaleTransform.ScaleX>
<Binding ElementName="SlideZoom" Path="Value" Mode="OneWay"/>
</ScaleTransform.ScaleX>
<ScaleTransform.ScaleY>
<Binding ElementName="SlideZoom" Path="Value" Mode="OneWay"/>
</ScaleTransform.ScaleY>
</ScaleTransform>
</TransformGroup>
</Grid.LayoutTransform>
</Grid>
</ScrollViewer>
</Grid>
<Slider Opacity="0.5" VerticalAlignment="Top" HorizontalAlignment="Left" Width="300" Grid.Row="1" Name="SlideZoom" Orientation="Horizontal" Minimum="0.1" Maximum="3" Value="1">
</Slider>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
</Grid>
</DataTemplate>
When I run the code I get two issues I don't understand:
I seem to only get a single ScrollViewer when I would expect a ScrollViewer per item. So if I add two tab items and make the canvas different sizes, the scroll bars are adjusted to the size of the biggest canvas only. I expected that the Shared=False attribute would create new instances of the template for each tab.
Maybe related to item 1 - if I stick a breakpoint on the constructor of MyDesignCanvas it gets hit when the first tab is added but not when other tabs are added. Only when I start closing tabs does the breakpoint get hit again - I would expect a hit on each tab addition.
I guess I don't really understand data templating enough, so can anyone explain what might be going on or point me at some resources that may help me diagnose this?
Thanks
I've realised what the issue is - the WPF TabControl does internal virtualization of tab content, so has been re-using the tab contents and just changing the data context despite me using Shared=False. See this SO question and this one too for more details.

How come I can only have one instance of a Silverlight UserControl per page?

Its pretty lame, but I tried adding two UserControl's to my Silverlight Page, and I get an exception telling me (with extensive digging) that the same control name has been used to the visual tree twice. So the controls inside my UserControl are named, so therefore I can include only one of this UserControl into the Page at a time. Is this true, or am I not realizing something? Has Microsoft truly given up on code-reuse? This is very lame.
Edits
For people who come here, I was getting this a System.Resources.MissingManifestResourceException exception. It took some time to figure out that the problem was ambiguous names in the visual tree. Hopefully this helps you. Below is the full exception text.
Further Edits
Here is my XAML:
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="HeaderText"
res:Strings.Assignment="Text=MachiningView_Name"/>
<sdk:TabControl Grid.Row="2">
<sdk:TabItem Header="Projects">
<ScrollViewer>
<Grid>
<controls:Organizer Margin="4" ItemsSource="{Binding ProjectSummaries}" Height="24" VerticalAlignment="Top">
<controls:Organizer.GroupDescriptions>
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=NoGroupingText" IsDefault="True" />
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=GroupOwnerEmailText">
<controls:OrganizerGroupDescription.GroupDescription>
<helpers:OwnerEmailGroupDescription />
</controls:OrganizerGroupDescription.GroupDescription>
</controls:OrganizerGroupDescription>
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=GroupStoreNumberText">
<controls:OrganizerGroupDescription.GroupDescription>
<helpers:StoreNumberGroupDescription />
</controls:OrganizerGroupDescription.GroupDescription>
</controls:OrganizerGroupDescription>
</controls:Organizer.GroupDescriptions>
</controls:Organizer>
</Grid>
</ScrollViewer>
</sdk:TabItem>
<sdk:TabItem Header="Machine Queues">
<ScrollViewer>
<Grid>
<controls:Organizer Margin="4" ItemsSource="{Binding ProjectSummaries}" Height="24" VerticalAlignment="Top">
<controls:Organizer.GroupDescriptions>
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=NoGroupingText" IsDefault="True" />
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=GroupOwnerEmailText">
<controls:OrganizerGroupDescription.GroupDescription>
<helpers:OwnerEmailGroupDescription />
</controls:OrganizerGroupDescription.GroupDescription>
</controls:OrganizerGroupDescription>
<controls:OrganizerGroupDescription res:Strings.Assignment="Text=GroupStoreNumberText">
<controls:OrganizerGroupDescription.GroupDescription>
<helpers:StoreNumberGroupDescription />
</controls:OrganizerGroupDescription.GroupDescription>
</controls:OrganizerGroupDescription>
</controls:Organizer.GroupDescriptions>
</controls:Organizer>
</Grid>
</ScrollViewer>
</sdk:TabItem>
</sdk:TabControl>
</Grid>
And here is my user control's XAML:
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=UserControl}">
<sdk:Label Content="Page:" VerticalAlignment="Center" Margin="0,0,5,0"/>
<sdk:DataPager Name="_projectSummariesPager"
Margin="0,0,5,0"
DisplayMode="FirstLastPreviousNextNumeric"
Source="{Binding Path=ItemsSource}"
PageSize="10"/>
<ComboBox Name="_itemPerPageCombo"
Margin="0,0,5,0"
SelectionChanged="_itemPerPageCombo_SelectionChanged"
SelectedItem="{Binding Path=SelectedPageSize, Mode=TwoWay}"
SelectedValuePath="Value"
ItemsSource="{Binding Path=PageSizes}"/>
<ComboBox Name="_groupDescription"
Margin="0,0,5,0"
SelectionChanged="_groupDescription_SelectionChanged"
SelectedItem="{Binding Path=SelectedGroupDescription, Mode=TwoWay}"
ItemsSource="{Binding Path=GroupDescriptions}"/>
</StackPanel>
Names given to elements in Xaml need to be unique within the namescope. Each execution of LoadComponent creates a new namescope. Hence the names within the UserControl will not conflict in the visual tree when multiple instances of the control were used.
So the answer to question as it stands right now is: because you are doing something wrong.
What the "something" is is unclear right now. Perhaps if you included your xaml in the question we can help you.
Edit
So reading between the lines this is what I'm guessing you are doing. You have a UserControl that has a number for properties and you want controls within the UserControl to bind to these properties so you are doing this:-
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=UserControl}">
This would indicate that you have added Name="UserControl" to the <UserControl.. element at the top of its xaml.
I can't quite find a way to reproduce your problem but I am aware of problems with earlier versions of SL where this approach is a problem. Personally I think its better to avoid setting properties that really belong to the external consumer of the component (its up to the page that is using you UserControl what its name is and whether it should have name at all).
Hence my approach to solve this "Bind to the UserControl itself" sort of Problem:-
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=LayoutRoot.Parent}">
where LayoutRoot is the name of the top level Grid which is the root of the UserControl content. This still binds to the UserControl itself via the Grid's Parent property. However this does not require a name to be added to the UserControl itself in its own xaml.
When you add the UserControl, make sure to assign it a unique name, ie:
<Page ...
<StackPanel>
<local:YourUserControl x:Name="Foo" />
<!-- Make sure not to duplicate x:Name/Name here! -->
<local:YourUserControl x:Name="Bar" />
</StackPanel>
</Page>

what is the best way to emulate XAML code inheritance?

I have a number of UserControl classes:
DataTypeWholeNumber
DataTypeLine
DataTypeDate
DateTypeDuration
etc.
They all inherit from a plain C# class which inherits from UserControl which has no XAML attached to it. I had to do it this way since I was getting errors saying that XAML could not be inherited.
The problem is that the XAML for each of these UserControls is basically the same, so I would like to find some way to at least emulate XAML inheritance so that I don't have to repeat this code for 20 different classes:
<dataTypes:BaseDataType x:Class="TestDependencyProperty827.DataTypes.DataTypeLine"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dataTypes="clr-namespace:TestDependencyProperty827.DataTypes">
<StackPanel Margin="{Binding Margin}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding LabelWidth}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock Text="{Binding Label}" FontSize="14"/>
<TextBlock FontSize="14" Text=":"/>
</StackPanel>
<TextBox Grid.Column="1" FontSize="12" HorizontalAlignment="Left"
Text="{Binding Text}"
Width="{Binding Width}"/>
</Grid>
</StackPanel>
</dataTypes:BaseDataType>
Has anyone run into this problem and found a solution to it?
Use a Style that applies to the base class:
<Style TargetType="BaseClass">
<Setter Property="Control.Template">
<Control.Value>
<StackPanel Margin="{Binding Margin}">
<!-- Rest of code here -->
</Control.Value>
</Style>
Also, I question the need for UserControls for every one of the base types - why can't you just reuse the same UserControl everywhere?
A XAML class can't inherit from a XAML class, but a normal class can inherit from a XAML class - so if the XAML for all of those is the same put that XAML in BaseDataType and crate all the derived types as normal non-WPF c# classes.
If you need to derive other XAML user controls from BaseDataType than this is not possible but you can use styles, data templates or control templates to share the XAML between diffrent controls.

Resources