I have created a User Control that is designed to simplify the use of a recursive popup dialog system in which a popup dialog can have a popup dialog open within it.
Here is the User Control's XAML:
<UserControl x:Class="SEA.WPF.View.Controls.DialogPresenter"
Name="This"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SEA.WPF.View.Controls"
xmlns:ts="clr-namespace:SEA.WPF.View.TemplateSelectors"
xmlns:c="clr-namespace:SEA.WPF.View.DataConverters"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<c:InstanceToVisibilityConverter x:Key="InstanceToVisibilityConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Grid Visibility="{Binding Dialog, Converter={StaticResource InstanceToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Grid.Row="1" Grid.Column="1">
<ContentControl Content="{Binding Path=Dialog, ElementName=This}"
ContentTemplateSelector="{Binding Path=DialogTemplateSelector, ElementName=This}" />
</Border>
<ContentControl Grid.RowSpan="3" Grid.ColumnSpan="3" Content="{Binding Path=Dialog.Dialog, ElementName=This}">
<ContentControl.ContentTemplateSelector>
<ts:InstanceOnlyTemplateSelector>
<ts:InstanceOnlyTemplateSelector.Template>
<DataTemplate>
<local:DialogPresenter Dialog="{Binding Path=Dialog.Dialog, ElementName=This}"
DialogTemplateSelector="{Binding Path=DialogTemplateSelector, ElementName=This}" />
</DataTemplate>
</ts:InstanceOnlyTemplateSelector.Template>
</ts:InstanceOnlyTemplateSelector>
</ContentControl.ContentTemplateSelector>
</ContentControl>
</Grid>
</UserControl>
Here is InstanceOnlyTemplateSelector:
using System.Windows;
using System.Windows.Controls;
namespace SEA.WPF.View.TemplateSelectors
{
public class InstanceOnlyTemplateSelector : DataTemplateSelector
{
public DataTemplate Template
{
get;
set;
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
return item == null ? null : Template;
}
}
}
The InstaceOnlyTemplateSelector is there so that the recursive DialogPresenter is only rendered when the child dialog is not null (thus avoiding a Stack Overflow cause by the recursive binding).
The problem is, that when the child dialog changes from null to something else then the recursive DialogPresenter does not render like it's parent. I have tried replacing the DialogPresenter with a Grid with Background equal to Brushes.Black and that made the whole screen black (as expected).
Why is the recursive instance of the DialogPresenter not rendering as expected?
Related
I have a UWP application:
My app command bar (XAML 2) manages TabView content (XAML 1). I need different command bars for different tab types. Now I using several frames in second XAML, and I can't change it from XAML 1.
How I can change XAML 2 UI from XAML 1 .cs file?
Thanks for any help.
UPD:
I have main XAML:
<Page
x:Class="Test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:NetChrom"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="BaseGrid">
<Grid.RowDefinitions>
<!-- titlebar -->
<RowDefinition x:Name="Titlebar" Height="30">
</RowDefinition>
<!-- toolbar -->
<RowDefinition x:Name="Toolbar" Height="110">
</RowDefinition>
<!-- main window -->
<RowDefinition>
</RowDefinition>
</Grid.RowDefinitions>
<Grid x:Name="TitlebarGrid" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*">
</ColumnDefinition>
</Grid.ColumnDefinitions>
<local:TitleBar/>
</Grid>
<Grid x:Name="ToolbarGrid" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="37*">
</ColumnDefinition>
<ColumnDefinition Width="27*"/>
</Grid.ColumnDefinitions>
<!-- toolbar -->
<local:Toolbar Grid.ColumnSpan="2"/>
</Grid>
<!-- content-->
<Grid x:Name="MainContent" Grid.Row="2" Background="AliceBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="325" MinWidth="120">
</ColumnDefinition>
<ColumnDefinition>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" Background="#F3F3F3">
<local:MainTabbar/>
</Grid>
<Grid Grid.Column="0" Background="LightBlue">
<local:FileManager/>
</Grid>
<controls:GridSplitter
Margin="0,10,10,0"
Opacity="0"
Background="Transparent"
GripperCursor="Default"
HorizontalAlignment="Left"
Grid.Column="1"
ResizeDirection="Auto"
ResizeBehavior="BasedOnAlignment"
CursorBehavior="ChangeOnSplitterHover"
Width="0">
<controls:GridSplitter.RenderTransform>
<TranslateTransform X="-8" />
</controls:GridSplitter.RenderTransform>
</controls:GridSplitter>
</Grid>
</Grid>
</Page>
and in this XAML there are two another XAML: MainTabbar (XAML 1) and Toolbar (XAML 2) from scheme.
This is Toolbar.xaml:
<UserControl
x:Class="Test.Toolbar"
x:Name="toolbarControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:local="using:Test"
xmlns:met="using:Test.Method"
xmlns:chr="using:Test.ChrOptions"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
d:DesignHeight="110"
d:DesignWidth="1920">
<Border CornerRadius="0,0,10,10" BorderBrush="#D4D4D4" BorderThickness="1,0,1,1" Background="#F3F3F3">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="110">
</RowDefinition>
</Grid.RowDefinitions>
<Grid x:Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition>
</ColumnDefinition>
<ColumnDefinition Width="320"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" HorizontalAlignment="Right">
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
</StackPanel>
</Grid>
<Grid Grid.Column="0">
<Frame x:Name="toolbarFrame"/> <!-- cmdbar frame>
</Grid>
</Grid>
</Grid>
</Border>
</UserControl>
This is MainTabbar:
<Page
x:Class="Test.MainTabbar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Test"
xmlns:met="using:Test.Method"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
d:DesignWidth="1595">
<Grid Margin="10,0,0,0">
<muxc:TabView x:Name="Tabs"
IsAddTabButtonVisible="False"
VerticalAlignment="Stretch"
TabCloseRequested="Tabs_TabCloseRequested"
AllowDropTabs="True"
CanDragTabs="False"
CanReorderTabs="True"
TabDroppedOutside="Tabs_TabDroppedOutside"
TabStripDragOver="Tabs_TabStripDragOver"
TabStripDrop="Tabs_TabStripDrop"
TabDragStarting="Tabs_TabDragStarting" >
<muxc:TabView.TabItems>
<muxc:TabViewItem Header="SampleMethod.met" IsClosable="False">
<muxc:TabViewItem.IconSource>
<muxc:SymbolIconSource Symbol="Placeholder" />
</muxc:TabViewItem.IconSource>
<!-- <Frame x:Name="MethodFrame"/> -->
<met:MethodTabView/>
</muxc:TabViewItem>
<muxc:TabViewItem Header="SampleChrome.chr" IsClosable="False">
<muxc:TabViewItem.IconSource>
<muxc:SymbolIconSource Symbol="Placeholder" />
</muxc:TabViewItem.IconSource>
<local:ChrView/>
</muxc:TabViewItem>
</muxc:TabView.TabItems>
<muxc:TabView.TabStripHeader>
<Grid x:Name="ShellTitlebarInset" Background="#F3F3F3" />
</muxc:TabView.TabStripHeader>
<muxc:TabView.TabStripFooter>
<Grid x:Name="CustomDragRegion" Background="#F3F3F3" />
</muxc:TabView.TabStripFooter>
</muxc:TabView>
</Grid>
</Page>
I need to get current tab type in MainTabbar.xaml.cs (it's ok). And then change Command Bar in Toolbar.xaml frame.
I wrote this procedure for change frame in Toolbar.xaml.cs:
public void setMetCmdbarMode()
{
toolbarFrame.Navigate(typeof(MethodToolbar), null);
}
But I don't know how I can call this function from MainTabbar class, or how I can translate tab type to Toolbar class.
After checking your code, you could try to create a custom event in the MainTabbar, and handle it in the MainPage. This event is triggered when the selected item of the TabView is changed. Then you could get notified in the MainPage and call method to change the Toolbar.
Here are the detailed steps:
Create a custom Event named TabItemChanged on the MainTabbar page and call it in the TabView_SelectionChanged event.
Handle the TabItemChanged in the MainPage
Change the content of the Toolbar as you want in the EventHandler based on the TabViewItem.
Code in MainTabbar:
public sealed partial class MainTabbar : Page
{
public event EventHandler TabItemChanged;
public MainTabbar()
{
this.InitializeComponent();
}
private void Tabs_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (this.TabItemChanged != null)
this.TabItemChanged(Tabs.SelectedItem, new EventArgs());
}
}
In the MainPage.Xaml
<local:MainTabbar TabItemChanged="MainTabbar_TabItemChanged"/>
In the MainPage.Xaml.cs
private void MainTabbar_TabItemChanged(object sender, EventArgs e)
{
MUXC.TabViewItem tabitem = sender as MUXC.TabViewItem;
switch (tabitem.Tag)
{
case "123":
Debug.WriteLine("FirstItemSelectecd");
//call method for toobar to change content
//like setMetCmdbarMode()
break;
case "234":
Debug.WriteLine("SecondItemSelectecd");
//call method for toobar to change content
//like setMetCmdbarMode()
break;
}
}
Update:
Give the toolbar a name in MainPage.Xaml
<local:Toolbar x:Name="myToolbar" Grid.ColumnSpan="2"/>
Then call it in the MainPage.Xam.cs:
switch (tabitem.Tag)
{
case "123":
Debug.WriteLine("FirstItemSelectecd");
myToolbar.setMetCmdbarMode();
break;
case "234":
Debug.WriteLine("SecondItemSelectecd");
break;
}
We have a VS extension. The user uses a ToolWindowPane to interact with the extension. The height and width of the ToolWindowPane depends on how the user has their VS environment set up, and currently the contents of the ToolWindowPane does not resize properly.
So here is the window:
public class SymCalculationUtilitiesWindow : ToolWindowPane
{
/// <summary>
/// Initializes a new instance of the <see cref="SymCalculationUtilitiesWindow"/> class.
/// </summary>
public SymCalculationUtilitiesWindow() : base(null)
{
this.Caption = "Sym Calculation Utilities";
this.ToolBar = new CommandID(new Guid(Guids.guidConnectCommandPackageCmdSet), Guids.SymToolbar);
// This is the user control hosted by the tool window; Note that, even if this class implements IDisposable,
// we are not calling Dispose on this object. This is because ToolWindowPane calls Dispose on
// the object returned by the Content property.
this.Content = new UtilitiesView();
}
}
So the UtilitiesView is the default view. Here is the xaml:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Sym.VisualStudioExtension" x:Class="Sym.VisualStudioExtension.Engines.UtilitiesView"
xmlns:engines="clr-namespace:Sym.VisualStudioExtension.Engines"
Background="{DynamicResource VsBrush.Window}"
Foreground="{DynamicResource VsBrush.WindowText}"
mc:Ignorable="d"
local:ViewModelLocator.AutoWireViewModel="True"
x:Name="MyToolWindow" Height="800" Width="400">
<UserControl.Resources>
<DataTemplate DataType="{x:Type engines:CalcEngineViewModel}">
<engines:CalcEngineView/>
</DataTemplate>
<DataTemplate DataType="{x:Type engines:TAEngineViewModel}">
<engines:TAEngineView/>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="207*" />
<RowDefinition Height="593*"/>
</Grid.RowDefinitions>
<Grid x:Name="MainContent"
Grid.Row="1" Grid.RowSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ContentControl Content="{Binding CurrentEngineViewModel}" Grid.RowSpan="2"/>
</Grid>
</Grid>
and the user makes a choice which determines the CurrentEngineViewModel.
The following is the xaml of one of the possible CurrentEngineViewModels:
<UserControl x:Class="Sym.VisualStudioExtension.Engines.CalcEngineView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="clr-namespace:Sym.Engines.Calculation.Builder.Domain;assembly=Sym.Engines.Calculation"
xmlns:core="clr-namespace:Sym.Core.Domain;assembly=Sym.Core"
xmlns:helper="clr-namespace:Sym.VisualStudioExtension.Helper_Classes"
xmlns:local="clr-namespace:Sym.VisualStudioExtension"
local:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="400">
<UserControl.Resources>
<ContextMenu>
...
</ContextMenu>
</UserControl.Resources>
<Grid Margin="-20,-20,-20,-20">
<Grid.RowDefinitions>
<RowDefinition Height="8*"/>
</Grid.RowDefinitions>
<TabControl x:Name="tabControl" HorizontalAlignment="Left" Height="617" Margin="20,54,0,0" VerticalAlignment="Top" Width="357">
<TabItem Header="Calculation Files">
<ListBox Name="CalcFilesListBox"
Margin="20" ItemsSource="{Binding CalcFilesList}"
ContextMenu="{StaticResource NewEditDeleteContextMenu}"
Tag="{x:Type core:CalcFile}">
...
</ListBox>
</TabItem>
<TabItem Header="Template Files" Height="22" VerticalAlignment="Top">
<TreeView ItemsSource="{Binding TemplateFamilyList}"
Margin="20"
ContextMenu="{StaticResource NewEditDeleteContextMenu}"
Tag="{x:Type domain:TemplateParameter}">
<TreeView.Resources>
...
</TreeView.Resources>
</TreeView>
</TabItem>
<TabItem Header="Advanced Calc Files">
<ListBox Margin="20"
ItemsSource="{Binding AdvancedCalcFilesList}"
ContextMenu="{StaticResource NewEditDeleteContextMenu}"
Tag="{x:Type domain:TemplateCalculation}">
...
</ListBox>
</TabItem>
</TabControl>
<Label x:Name="label" Content="{Binding Path=Title}" HorizontalAlignment="Left" Height="27" Margin="10,22,0,0" VerticalAlignment="Top" Width="367"/>
</Grid>
It seems to me that on the ToolWindowPane, there is a Grid, and on the Grid another Grid, and on that Grid, a Tabcontrol. From this post it seems that some controls do not resize. So would that mean that the TabControl can't resize even if it is on a Grid?
When the user resizes the ToolWindowPane, the contents does not resize.
How can I achieve correct resizing in this situation?
The base of the problem is the explicit Width and Height values are being set and preventing the controls from fitting into their container.
To make the page salable across resolutions/devices, you must ensure that there are no fixed width/height property specified; instead we can use them in percentage (%) which will make the controls scale based on available viewport. Try replacing all the fixed height & width properties for your control with percentages.
if for some reasons the controls are getting squeezed you can try providing minHeight & minWidth to the control as documented here https://www.w3schools.com/cssref/pr_dim_min-height.asp
I have a window that expands to left and to the right.
Simplified example:
<Window x:Class="Application1.Windows.Test"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow"
SizeToContent="Width" Height="250">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <!--Expander LEFT-->
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="175" /> <!--Red Content -->
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="Auto"/> <!--Expander RIGHT-->
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="*"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Expander Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="3"
Margin="5"
ExpandDirection="Left">
<Grid Width="200">
</Grid>
</Expander>
<Grid Grid.Column="2"
Grid.RowSpan="3"
Background="Red"/>
<Expander Grid.Column="4"
Grid.Row="0"
Grid.RowSpan="3"
Margin="5"
ExpandDirection="Right">
<Grid Width="200">
</Grid>
</Expander>
</Grid>
Here you can see what the problem is:
I've already had a look on WPF - Expand Window to the Left.
The solution kind of works but that is only solving half of the problem.
How to do that for Left AND Right ?
UPDATE
I do not want the Expander columns to be fixed. They should just show the minimal space needed for the expander
One approach that will work is this:
(But I'm somehow unsatisfied with this solution)
Create an Enum to store the last Action in:
public enum ExpandActions
{
ExpandRight,
ExpandLeft,
CollapsRight,
CollapseLeft
}
Then I added the handlers for Expand & Collapse to my Expanders in xaml.
At last override SizeChanged on the Window as in WPF - Expand Window to the Left.
We only want this behavior, when expanding to left - otherwise we would kill our 'expand-to-right' behavior.
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
if (!sizeInfo.WidthChanged)
{
base.OnRenderSizeChanged(sizeInfo);
return;
}
Hide();
base.OnRenderSizeChanged(sizeInfo);
//Last action was on left expander
if(_lastAction == ExpandActions.CollapseLeft || _lastAction == ExpandActions.ExpandLeft)
{
Left -= (sizeInfo.NewSize.Width - sizeInfo.PreviousSize.Width);
}
Show();
}
Good point about this is that expansion out of screen could be handled.
It works but I guess it's not the best solution.
The result is this:
First, let me show you how my code is cut.
I have this code in a xaml UC (eventsUC.xaml) :
<UserControl x:Class="QuimeO.UserControls.Lists.EventsListUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ToggleSwitch="clr-namespace:ToggleSwitch;assembly=ToggleSwitch"
mc:Ignorable="d"
Width="477"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" Width="auto" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ItemsControl Grid.Row="0" BorderThickness="0" x:Name="eventsList" ScrollViewer.VerticalScrollBarVisibility="Auto" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ItemsControl.Resources>
<ResourceDictionary x:Name="eventslisttempplate" Source="EventsListTemplate.xaml" />
</ItemsControl.Resources>
</ItemsControl>
</ScrollViewer>...
My EventsListTemplate.xaml looks like this :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="QuimeO.UserControls.Lists.EventsListTemplate"
xmlns:apiNamespace="clr-namespace:QuimeO.DBO"
>
<DataTemplate DataType="{x:Type apiNamespace:EventsDictionary}">
<StackPanel Orientation="Vertical">
<Border BorderBrush="LightGray" BorderThickness="0,0,0,1" Margin="0,5,0,0">
<TextBlock HorizontalAlignment="Right" Foreground="Gray" Text="{Binding FormatedDate}" FontSize="14"></TextBlock>
</Border>
<ListView Grid.Row="0" x:Name="eventsList" ItemsSource="{Binding Events}" BorderThickness="0" MouseDoubleClick="eventsList_MouseDoubleClick">
</ListView>
</StackPanel>
</DataTemplate>
</ResourceDictionary>
And my EventsListTemplate.xaml.cs code behind looks like this
public partial class EventsListTemplate : ResourceDictionary
{
public Delegate MainWindowControlPointer;
private void eventsList_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var ev = ((sender as ListView).SelectedItem as ListViewItem).DataContext as Event;
System.Diagnostics.Debug.WriteLine(ev.Name);
this.MainWindowControlPointer.DynamicInvoke(ev.Ancestors.Root, new Element() { Category = ev.Category, Id = ev.Id, Name = ev.Name });
}
}
When I click on an item of my listview in my template, it trigger the eventsList_MouseDoubleCkick and I can retrieve my event.
However, I would like to trigger an action in the UC where the template is created (first source code block).
To do that, I just want to create a delegate in my Template (technicaly, in a perfect world, something like "this.rd_eventslisttemplate.MainWindowControlPointer = ... "). But, I don't know how to do it or if this is even possible.
After encrypting your question for a while I think I got it.
There is a nice method called VisualTreeHelper.GetParent() which gets you the parent of a control in VisualTree.
Now to your problem when you catch your event in EventsListTemplate you will need to call GetParent() few times till you finally get the instance of your UserControl.
Thats it.
I have a simple application with App.xaml, MainWindow.xaml and a Person class. When I don't specify the template, my ValidateOnDataErrors works perfectly, putting a red border around my textbox when it is in error. However, as soon as I insert the ' Template="{StaticResource WindowTemplate}" ' in the Window tag of my MainWindow.xaml, the field is still validated but the red border disappears.
App.xaml :
<Application x:Class="WpfPOC.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ControlTemplate TargetType="Window" x:Key="WindowTemplate">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Control x:Name="FocusCatcher"></Control>
<TextBlock>Menu Section</TextBlock>
<ContentPresenter Grid.Row="1" />
<StatusBar Height="23" VerticalAlignment="Bottom" Grid.Row="2">
<TextBlock Text="Current Editing Mode" />
</StatusBar>
</Grid>
</ControlTemplate>
</Application.Resources>
</Application>
MainWindow.xaml :
<Window x:Class="WpfPOC.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:data="clr-namespace:WpfPOC"
Template="{StaticResource WindowTemplate}"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<data:Person x:Key="myDataSource" Name="Joe"/>
</Window.Resources>
<Grid>
<TextBox Height="23" Width="120" Text="{Binding Source={StaticResource myDataSource}, Path=Name, ValidatesOnDataErrors=True}" />
</Grid>
</Window>
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace WpfPOC
{
public class Person : IDataErrorInfo
{
public string Name { get; set; }
#region IDataErrorInfo Members
public string Error
{
get { return string.Empty; }
}
public string this[string columnName]
{
get { return "Simulated error"; }
}
#endregion
}
}
Thank you in advance for your help.
This happens because the default ControlTemplate used for displaying validation errors (draws a red border around the control) uses the AdornerLayer.
You have created a new ControlTemplate for the entire Window and left out the AdornerDecorator (which the default ControlTemplate for Window supplies)
So just wrap your new ControlTemplate with a AdornerDecorator like so:
<ControlTemplate TargetType="Window" x:Key="WindowTemplate">
<AdornerDecorator>
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Control x:Name="FocusCatcher"></Control>
<TextBlock>Menu Section</TextBlock>
<ContentPresenter Grid.Row="1" />
<StatusBar Height="23" VerticalAlignment="Bottom" Grid.Row="2">
<TextBlock Text="Current Editing Mode" />
</StatusBar>
</Grid>
</AdornerDecorator>
</ControlTemplate>