I have the following classes / XAML that define my tabs (using SimpleMVVM in case that matters):
Tabs Interface
public interface ITabViewModel
{
String Header { get; set; }
Visibility Visibility { get; set; }
void TabSelected();
}
Tabs VM
public class TabsViewModel : ViewModelBase<TabsViewModel>
{
#region Properties
public ObservableCollection<ITabViewModel> Tabs { get; set; }
public object SelectedTabViewModel
{
get
{
if (this._SelectedTabViewModel == null)
{
_SelectedTabViewModel = Tabs[0];
}
return _SelectedTabViewModel;
}
set
{
if (this._SelectedTabViewModel != value)
{
this._SelectedTabViewModel = value;
NotifyPropertyChanged(m => m.SelectedTabViewModel);
}
}
}
private object _SelectedTabViewModel;
#endregion Properties
#region Constructors
// Default ctor
public TabsViewModel()
{
Tabs = new ObservableCollection<ITabViewModel>();
Tabs.Add((App.Current.Resources["Locator"] as ViewModelLocator).PropertiesViewModel);
Tabs.Add((App.Current.Resources["Locator"] as ViewModelLocator).SystemSetupViewModel);
}
}
Tabs UserControl
<UserControl x:Class="AutomatedSQLMigration.Views.TabsUserControl"
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:v="clr-namespace:AutomatedSQLMigration.Views"
xmlns:vm="clr-namespace:AutomatedSQLMigration.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding TabsViewModel, Source={StaticResource Locator}}">
<TabControl ItemsSource="{Binding Tabs}"
SelectedItem="{Binding SelectedTabViewModel}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:PropertiesViewModel}">
<v:PropertiesUserControl />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:SystemSetupViewModel}">
<v:SystemSetupUserControl />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="Width" Value="120" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</UserControl>
Properties VM
...
public void TabSelected()
{
Log.Write(LogLevel.Debug, "Selected tab 'Rules'");
}
...
I would like to wire this up such that when the tab is selected, the TabSelected() method is fired for the selected tab. Can someone provide an example of how to do this?
I found another post that mentions this method:
TabItem item = new TabItem();
MyCustomControl mcc = new MyCustomControl();
item.Content = mcc;
Selector.AddSelectedHandler(item, (s,e) =>
{
selectedControl = mcc;
});
but am not sure how I would implement this? Would I apply this to the TabControl VM or each individual user control VM?
How about adding the line in the selected tab setter:
this._SelectedTabViewModel.TabSelected();
Related
Situation
I have to change the content of the Flyout Item in GridView. So I am creating ControlTemplate in Page.Resources and setting it in ContentControl which is inside Flyout.
Problem
I have a ComboBox in ControlTemplate. Now I want to set the ItemsSource of ComboBox to List<string> (_easingType) which is declared in MainPage
Question
How to Bind/Set ItemsSource of ComboBox in ControlTemplate?
Code
I have removed the unnecessary parts of the code
XAML
<Page.Resources>
<ControlTemplate x:Key="BlurEditFlyout">
....
<ComboBox ItemsSource="{Bind it to the _esaingType}" />
....
<ControlTemplate x:Key="BlurEditFlyout">
</Page.Resources>
<GridView ItemsSource="{x:Bind _items}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:MethodData">
<StackPanel>
....
<Button Visibility="{x:Bind EditButtonVisibility}">
<Button.Flyout>
<Flyout>
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
</Style>
</Flyout.FlyoutPresenterStyle>
<ContentControl Template="{x:Bind FlyoutTemplate}"/>
</Flyout>
</Button.Flyout>
<SymbolIcon Symbol="Edit"/>
</Button>
....
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Code Behind
public sealed partial class MainPage : Page
{
ObservableCollection<MethodData> _items = new ObservableCollection<MethodData>();
List<string> _easingType = new List<string>(Enum.GetNames(typeof(EasingType)).ToArray());
Dictionary<MethodName, ControlTemplate> _buttonFlyoutDictionary = new Dictionary<MethodName, ControlTemplate>();
public MainPage()
{
this.InitializeComponent();
LoadFlyoutResources();
_items.Add(GetMethodData(MethodName.Blur));
}
private void LoadFlyoutResources()
{
_buttonFlyoutDictionary.Add(MethodName.Blur, (ControlTemplate)Resources["BlurEditFlyout"]);
.....
}
private MethodData GetMethodData(MethodName methodName)
{
_buttonFlyoutDictionary.TryGetValue(methodName, out ControlTemplate flyoutTemplate);
return new MethodData(methodName, flyoutTemplate);
}
}
public class MethodData
{
public string Name { get; set; }
public ControlTemplate FlyoutTemplate { get; set; }
public Visibility EditButtonVisibility { get; set; }
public MethodData(MethodName name, ControlTemplate flyoutTemplate)
{
Name = name.ToString();
FlyoutTemplate = flyoutTemplate;
EditButtonVisibility = (name == MethodName.Then) ? Visibility.Collapsed : Visibility.Visible;
}
}
public enum MethodName
{
Blur,
....
}
Full Code
AnimationSetSamplePage.zip
Your DataContext in the Flyout control is actually each item in "_items". You'll want to create a DataContext proxy to get to your Page's DataContext. You can follow either of these two links to create the proxy.
https://weblogs.asp.net/dwahlin/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls
http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
The gist of it is you'll want to create a proxy that you can reference as a static resource. Following the first link, you'll do something like this:
public class DataContextProxy : FrameworkElement
{
public DataContextProxy()
{
this.Loaded += new RoutedEventHandler(DataContextProxy_Loaded);
}
void DataContextProxy_Loaded(object sender, RoutedEventArgs e)
{
Binding binding = new Binding();
if (!String.IsNullOrEmpty(BindingPropertyName))
{
binding.Path = new PropertyPath(BindingPropertyName);
}
binding.Source = this.DataContext;
binding.Mode = BindingMode;
this.SetBinding(DataContextProxy.DataSourceProperty, binding);
}
public Object DataSource
{
get { return (Object)GetValue(DataSourceProperty); }
set { SetValue(DataSourceProperty, value); }
}
public static readonly DependencyProperty DataSourceProperty =
DependencyProperty.Register("DataSource", typeof(Object), typeof(DataContextProxy), null);
public string BindingPropertyName { get; set; }
public BindingMode BindingMode { get; set; }
}
You should use public access modifier for _easingType
public List<string> _easingType = new List<string>(Enum.GetNames(typeof(EasingType)).ToArray());
In MainPage.xaml
<Page.Resources>
<local:DataContextProxy x:Key="DataContextProxy" />
<ControlTemplate x:Key="BlurEditFlyout">
....
<ComboBox ItemsSource="{Binding Source={StaticResource DataContextProxy}, Path=DataSource._easingType}" />
....
<ControlTemplate x:Key="BlurEditFlyout">
</Page.Resources>
...
How to Bind/Set ItemsSource of ComboBox in ControlTemplate?
I'm not sure if you have deep reasons for asking this question, but directly to reply this question, we could just set the string list _esaingType as the value of DataContext property and binding it. For example:
XAML
<Page.Resources>
<ControlTemplate TargetType="FlyoutPresenter" x:Key="BlurEditFlyout" >
...
<ComboBox ItemsSource="{Binding}" />
...
</ControlTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button>
<Button.Flyout>
<Flyout>
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="Template" Value="{StaticResource BlurEditFlyout}">
</Setter>
</Style>
</Flyout.FlyoutPresenterStyle>
<!--<ContentControl Template="{StaticResource BlurEditFlyout}"/>-->
</Flyout>
</Button.Flyout>
<SymbolIcon Symbol="Edit"/>
</Button>
</Grid>
Code behind
List<string> _easingType = new List<string>();
public MainPage()
{
this.InitializeComponent();
_easingType.Add("test2");
_easingType.Add("test1");
this.DataContext = _easingType;
}
Any concerns on this way or any issues when using this on your side please kindly tell me I will follow up in time. More details please reference Data binding in depth.
I am working on a WPF application where I want to use TabControl with ItemTemplate and ContentTemplate. I have a textblock in the ItemTemplate (for Header) and another textblock in the ContentTemplate(for Content).
I am binding a list to TabControl in constructor from code behind.
In Window loaded event, I want to loop over all tab items, access textblock in content template (Name="txt1") for each tab and set different text to textblock in each tab.
Below is my XAML:
<TabControl x:Name="mainTabs">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Name="txt1"></TextBlock>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
Code behind:
public MainWindow()
{
InitializeComponent();
// Read tabs data from xml file
List<MyTab> lst = ReadTabsFromXml();
mainTabs.ItemsSource = lst;
}
public class MyTab
{
public string Header { get;set; }
public string Content { get; set; }
}
Please help me with this.
You don't need to do that. Just store your MyTab classes in an ObservableCollection<MyTab> instead of a List<MyTab>, and set the ItemsSource to the collection. The TabControl will update automatically.
EDIT: I've updated the answer, with a solution regarding using Gecko browser. You can wrap the Gecko browser in a UserControl that you use in each TabItem. Also note that a TabControl recreates the the TabItem every time you switch tabs, which also causes the webpage to reload. You can get around this by using e.g. TabControEx instead of TabControl (https://stackoverflow.com/a/9802346/6839733). But this is not related to the Gecko browser or to binding URL's from a collection - it's just how the TabControl works.
MainWindow.xaml:
<TabControl x:Name="MyTabControl">
<TabControl.Resources>
<DataTemplate x:Key="MyTabContentTemplate" x:Shared="False">
<local:GeckoBrowser Uri="{Binding Path=Uri}" />
</DataTemplate>
<Style TargetType="{x:Type TabItem}">
<Setter Property="ContentTemplate" Value="{StaticResource MyTabContentTemplate}" />
</Style>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public ObservableCollection<WebPageInfo> WebPageCollection { get; set; }
public MainWindow()
{
InitializeComponent();
// Read tabs data from xml file
//lst = ReadTabsFromXml();
WebPageCollection = new ObservableCollection<WebPageInfo>();
WebPageCollection.Add(new WebPageInfo() { Header = "Tab1", Uri = "https://www.amazon.com/" });
WebPageCollection.Add(new WebPageInfo() { Header = "Tab2", Uri = "https://www.cnn.com/" });
WebPageCollection.Add(new WebPageInfo() { Header = "Tab3", Uri = "https://www.microsoft.com/" });
WebPageCollection.Add(new WebPageInfo() { Header = "Tab4", Uri = "https://www.facebook.com/" });
MyTabControl.ItemsSource = WebPageCollection;
MyTabControl.SelectedIndex = 0;
}
public class WebPageInfo
{
public string Header { get; set; }
public string Uri { get; set; }
}
}
GeckoBrowser.xaml:
<UserControl x:Class="WpfApplication1.GeckoBrowser"
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:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Border x:Name="MyBorder" Background="Black" Margin="0" />
</UserControl>
GeckoBrowser.xaml.cs:
public partial class GeckoBrowser : UserControl
{
public static readonly DependencyProperty UriProperty =
DependencyProperty.Register("Uri", typeof(string), typeof(GeckoBrowser), new FrameworkPropertyMetadata(null));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public GeckoBrowser()
{
InitializeComponent();
Xpcom.Initialize("Firefox");
Loaded += GeckoBrowser_Loaded;
}
private void GeckoBrowser_Loaded(object sender, RoutedEventArgs e)
{
WindowsFormsHost host = new WindowsFormsHost();
GeckoWebBrowser browser = new GeckoWebBrowser();
browser.Navigate(Uri);
host.Child = browser;
MyBorder.Child = host;
}
}
I would like to be able to style the ContentPresenter used for rendering the cells of a GridView. However if I set a style targeting ContentPresenter generally then it will target ContentPresenter instances within ContentPresenters which I do not want to do. I only want to style the first level of content presenters found.
Is this possible? Something like this
<Style Target="GridView">
<Style.Resource>
<Style Target="ContentPresenter" Depth=1>
<Setter Property="Margin" Value="1"/>
</Style>
</Style.Resources>
</Style>
where Depth=1 is an invented property.
You could possibly do this with a DataTemplateSelector - by setting a style for a ContentPresenter and ensuring it used a ContentTemplateSelector.
My example is simplified and doesn't use a GridView - but the concept is the same.
If you had the following DataTemplateSelector:
public class DepthTemplateSelector : DataTemplateSelector
{
public DataTemplate InDepthTemplate { get; set; }
public Type Type { get; set; }
public int Depth { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var next = container;
int itemsControlCount = 0;
while (VisualTreeHelper.GetParent(next) != null)
{
var current = VisualTreeHelper.GetParent(next);
if (current.GetType() == this.Type)
{
itemsControlCount++;
}
next = current;
}
if (itemsControlCount <= this.Depth)
{
return this.InDepthTemplate;
}
return base.SelectTemplate(item, container);
}
}
Then wire this up in XAML with whatever template you wanted to use for content presenters with less than a certain depth:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<w:DepthTemplateSelector x:Key="DepthTemplateSelector" Depth="2" Type="{x:Type ContentPresenter}">
<w:DepthTemplateSelector.InDepthTemplate>
<DataTemplate DataType="{x:Type w:Model}">
<StackPanel>
<TextBlock Text="{Binding Description}" Foreground="Red" />
<ItemsControl ItemsSource="{Binding Models}" Margin="20,0,0,0" />
</StackPanel>
</DataTemplate>
</w:DepthTemplateSelector.InDepthTemplate>
</w:DepthTemplateSelector>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="ContentTemplateSelector" Value="{StaticResource DepthTemplateSelector}" />
</Style>
<DataTemplate DataType="{x:Type w:Model}">
<StackPanel>
<TextBlock Text="{Binding Description}" />
<ItemsControl ItemsSource="{Binding Models}" Margin="20,0,0,0" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<w:ViewModel />
</Window.DataContext>
<ListView ItemsSource="{Binding Models}" />
</Window>
So the XAML creates and configures the DataTemplateSelector but also ensures all ContentPresenters use it by setting a default ContentPresenter style.
This will then give you the following effect (with Depth set to 2):
This is based on the following view model, which uses a recursive structure to illustrate the point:
public class ViewModel
{
public ViewModel()
{
this.Models = new List<Model>
{
new Model
{
Description = "ModelA",
Models = new List<Model>
{
new Model { Description = "ModelA1" },
new Model { Description = "ModelA2" }
}
},
new Model
{
Description = "ModelB",
Models = new List<Model>
{
new Model { Description = "ModelB1" },
new Model
{
Description = "ModelB2",
Models = new List<Model>
{
new Model { Description = "ModelB2i" },
new Model { Description = "ModelB2ii" }
}
}
}
}
};
}
public List<Model> Models { get; set; }
}
public class Model
{
public string Description { get; set; }
public List<Model> Models { get; set; }
}
I'm very new to MVVM and WPF. I'm trying to build a tabcontrol with tabpages presented as usercontrols and i can't find the reason why the usercontrols don't get loaded when i switch between the tabs.
public partial class WndMain : Window
{
public WndMain()
{
InitializeComponent();
var ViewModelWndMain = new ViewModelWndMain();
this.DataContext = ViewModelWndMain;
}
}
Each tabItem has it's own ViewModel:
<Window x:Class="EasyBulking.WndMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:EasyBulking.ViewModels"
xmlns:Tabs="clr-namespace:EasyBulking.GUI"
Title="WndMain" Height="350" Width="525">
<Grid>
<TabControl x:Name="TabsWndMain"
ItemsSource="{Binding Tabs}"
SelectedItem="{Binding SelectedTab, Mode=TwoWay}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type ViewModels:ViewModelTabProfile}">
<Tabs:TabProfile />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:ViewModelTabNutrition}">
<Tabs:TabNutrition />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:ViewModelTabTraining}">
<Tabs:TabTraining />
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding tabName}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Grid>
The corresponding ViewModel:
class ViewModelWndMain : ViewModelBase
{
private ObservableCollection<ViewModelTab> tabs = new ObservableCollection<ViewModelTab>();
private ViewModelTab selectedTab;
private ResourceManager resourceManager { get; set; }
public ViewModelWndMain ()
{
resourceManager = new ResourceManager("EasyBulking.Properties.Resources", Assembly.GetExecutingAssembly());
Tabs.Add(new ViewModelTabProfile(resourceManager.GetString("tabProfile")));
Tabs.Add(new ViewModelTabProfile(resourceManager.GetString("tabNutrition")));
Tabs.Add(new ViewModelTabProfile(resourceManager.GetString("tabTraining")));
SelectedTab = Tabs[0];
}
public ObservableCollection<ViewModelTab> Tabs
{
get
{
return tabs;
}
}
public ViewModelTab SelectedTab
{
get { return selectedTab; }
set {
selectedTab = value;
this.RaisePropertyChangedEvent("SelectedTab");
}
}
}
The ProperyChanged event fires but the UI just doesn't update when i switch the tabs.
abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
OK, just to close this question on a regular answer, here we go:
The code that adds the tabs' viewmodels inserts the same objects for all three tab pages:
Tabs.Add(new ViewModelTabProfile(resourceManager.GetString("tabProfile")));
Tabs.Add(new ViewModelTabProfile(resourceManager.GetString("tabNutrition")));
Tabs.Add(new ViewModelTabProfile(resourceManager.GetString("tabTraining")));
The resource-loaded header text masks that fact and it seems that the pages aren't swapping when in fact they swap from one control to the same type of control again.
i have a simple Control with a collection of elements. I want to add elements in xaml and bind to the element.
However when i bind to Bar.Value in xaml it never works. Minimal example:
[ContentProperty("Bars")]
public class FooControl : Control
{
private ObservableCollection<IBar> _bars = new ObservableCollection<IBar>();
public ObservableCollection<IBar> Bars { get { return _bars; } }
}
public interface IBar
{
string Value { get; }
}
public class Bar : DependencyObject, IBar
{
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(Bar), new PropertyMetadata("<not set>"));
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
}
<Window x:Class="WpfTestApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:this="clr-namespace:WpfTestApplication"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="200" Width="1000">
<Window.Resources>
<Style TargetType="this:FooControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="this:FooControl">
<ItemsControl ItemsSource="{Binding Bars, RelativeSource={RelativeSource TemplatedParent}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Window.DataContext>
<sys:String>from DataContext</sys:String>
</Window.DataContext>
<Grid>
<this:FooControl>
<this:Bar Value="directly set"/>
<this:Bar Value="{Binding Source=from_binding_source}"/>
<this:Bar Value="{Binding}"/>
<this:Bar Value="{Binding Text, ElementName=SomeTextBlock}"/>
</this:FooControl>
<TextBlock Text="from TextBox" Name="SomeTextBlock" Visibility="Collapsed"/>
</Grid>
</Window>
output
directly set
from_binding_source
"<not set>"
"<not set>"
debug output
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Text; DataItem=null; target element is 'Bar' (HashCode=26568931); target property is 'Value' (type 'String')
Any suggestion how to get it to work?
My current workaround is to define the bindings in code but this is a lot more code and looking at the xaml its not obvious which bindings do exists. (see my answer for workaround code)
dont know if this helps but
[ContentProperty("Bars")]
public class FooControl : Control
{
private ObservableCollection<object> _bars = new ObservableCollection<object>();
public ObservableCollection<object> Bars { get { return _bars; } }
}
xaml
<this:FooControl>
<this:Bar Value="directly set"/>
<this:Bar Value="{Binding Source=from_binding_source}"/>
<TextBlock Text="{Binding}"/>
<TextBlock Text="{Binding Text, ElementName=SomeTextBlock}"/>
</this:FooControl>
you get your desired result
my workaround so far
<this:Bar x:Name="bar3" />
<this:Bar x:Name="bar4" />
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var bar3 = (DependencyObject)FindName("bar3");
BindingOperations.SetBinding(bar3, Bar.ValueProperty, new Binding("DataContext") { Source = this });
var bar4 = (DependencyObject)FindName("bar4");
BindingOperations.SetBinding(bar4, Bar.ValueProperty, new Binding("Text") { Source = FindName("SomeTextBlock") });
}