I'm creating a custom ItemsControl that contains a grid for display whatever. I'd like the user to be able to use datatemplates for displaying that whatever, but how do I go about doing that?
I know how to create the templates, but I'm not sure how to go about applying a template such that the items are located properly within the grid (my code) and each item is displayed as the user wants (via the datatemplate).
-- edit --
There appears to be a little confusion as to what I'm asking. Imagine I wanted to create my own ListView from scratch using a Grid for the layout (that's not what I'm actually doing, but as an example ... ). Given a DataTemplate from the user, how do I use that to ensure the elements inside each grid cell are displayed according to the template?
Your control can expose its own property/properties, which you declare in your code-behind.
If you need a single DataTemplate, then you can expose a property of type DataTemplate. When a user declares your control type in XAML, she can provide the template:
<ns:YourControl>
<ns:YourControl.DataTemplate>
<DataTemplate>
…
</DataTemplate>
</ns:YourControl.DataTemplate>
</ns:YourControl>
In your own control, you consume this by binding to the DataTemplate property. Be sure to reference the control itself in your Binding, rather than the DataContext. You'll probably want a default DataTemplate or throw a useful Exception in the event that the user does not specify a DataTemplate.
You can give the user some additional flexibility if you expose a property of type DataTemplateSelector and then apply that to your items, if the data types are disparate or the user is likely to want different templates under different circumstances.
Example
MyControl.xaml
<UserControl x:Class="MyNamespace.MyControl"
x:Name="ThisControl">
<ItemsControl ItemTemplate="{Binding ItemTemplate, ElementName=ThisControl}" />
</UserControl>
MyControl.xaml.cs
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
public static readonly DependencyProperty ItemTemplateProperty
= DependencyProperty.Register("ItemTemplate", typeof (DataTemplate),
typeof (MyControl), new PropertyMetadata(default(DataTemplate)));
public DataTemplate ItemTemplate
{
get { return (DataTemplate) GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
// Other dependency properties (ItemsSource, SelectedItem, etc.)
}
The consumer:
<Grid>
<ns:MyControl ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}">
<ns:MyControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2"
BorderBrush="Black">
<TextBlock Foreground="DarkGray"
Text="{Binding Name}"
Margin="4" />
</Border>
</DataTemplate>
</ns:MyControl.ItemTemplate>
</ns:MyControl>
</Grid>
Update
Okay, here is a working example of populating the Grid and using the DataTemplate.
MyControl exposes a property, ItemsSource, which allows the consumer to bind to a collection in her view-model. MyControl also exposes a property, ItemTemplate, which allows a consumer to specify how to display those items (again, you could also allow the user to specify a DataTemplateSelector).
In the code-behind, when the source collection changes, we
create a ColumnDefinition for each item,
wrap each item inside another class that exposes Row and Column properties, and
add each wrapped item to a private collection, which is what we actually bind to in our control.
First, the XAML:
<UserControl x:Class="WpfApplication1.MyControl"
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"
mc:Ignorable="d"
x:Name="ThisControl"
d:DesignHeight="300" d:DesignWidth="300">
<ItemsControl x:Name="ItemsControl"
ItemsSource="{Binding BindableItems, ElementName=ThisControl, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Grid.Row" Value="{Binding Row}" />
<Setter Property="Grid.Column" Value="{Binding Column}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{Binding Content}"
ContentTemplate="{Binding ItemTemplate, ElementName=ThisControl}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</UserControl>
And the code-behind:
using System.Collections;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
"ItemsSource", typeof (IEnumerable), typeof (MyControl),
new PropertyMetadata(default(IEnumerable), OnItemsSourceChanged));
public IEnumerable ItemsSource
{
get { return (IEnumerable) GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
// This is the DataTemplate that the consumer of your control specifies
public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
"ItemTemplate", typeof (DataTemplate), typeof (MyControl), new PropertyMetadata(default(DataTemplate)));
public DataTemplate ItemTemplate
{
get { return (DataTemplate) GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
// This is declared private, because it is only to be consumed by this control
private static readonly DependencyProperty BindableItemsProperty = DependencyProperty.Register(
"BindableItems", typeof (ObservableCollection<object>), typeof (MyControl), new PropertyMetadata(new ObservableCollection<object>()));
private ObservableCollection<object> BindableItems
{
get { return (ObservableCollection<object>) GetValue(BindableItemsProperty); }
set { SetValue(BindableItemsProperty, value); }
}
private static void OnItemsSourceChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var myControl = dependencyObject as MyControl;
if (myControl == null)
{
return;
}
// Get reference to the Grid using reflection. You could also walk the tree.
var grid = (Grid) typeof (ItemsControl).InvokeMember("ItemsHost",
BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance,
null, myControl.ItemsControl, null);
var columns = grid.ColumnDefinitions;
columns.Clear();
myControl.BindableItems.Clear();
var items = args.NewValue as IEnumerable;
if (items != null)
{
var columnIndex = 0;
foreach (var item in items)
{
columns.Add(new ColumnDefinition{ Width = GridLength.Auto });
var container = new MyItem
{
Row = columnIndex,
Column = columnIndex++,
Content = item
};
myControl.BindableItems.Add(container);
}
}
}
}
public class MyItem
{
public object Content { get; set; }
public int Row { get; set; }
public int Column { get; set; }
}
}
Related
I have UserControl called EditorView that shows different "editors" (other user controls) based on its Content.
This is EditorView just to test the binding I replaced the FontEditor with TextBlock:
<UserControl x:Class="TrikeEditor.UserInterface.EditorView" ...>
<UserControl.Resources>
<DataTemplate DataType="{x:Type te_texture:Texture}">
<teuied:TextureEditor TextureName="{Binding Path=Name}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type te_font:Font}">
<!--<teuied:FontEditor/>-->
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</UserControl.Resources>
<UserControl.Template>
<ControlTemplate TargetType="{x:Type UserControl}">
<ContentPresenter Content="{TemplateBinding Content}" x:Name="EditorPresenter"/>
</ControlTemplate>
</UserControl.Template>
</UserControl>
The right template is getting picked based on the EditorView.Content and in the case of TextBlock the binding works as desired but in the case of TextureEditor the TextureName property isn't.
Here is snippet from the TextureEditor:
public partial class TextureEditor : UserControl
{
public static readonly DependencyProperty TextureNameProperty = DependencyProperty.Register("TextureName", typeof(string), typeof(TextureEditor));
public string TextureName
{
get { return (string)GetValue(TextureNameProperty); }
set { SetValue(TextureNameProperty, value); }
}
public TextureEditor()
{
InitializeComponent();
}
}
Is there anything special that I have to do since I'm using UserControl? Maybe being different namespace is the problem?
The User Control shouldn't affect it; the difference is that you're implementing your own dependency property (rather than using the existing one Text in TextBlock). You have to set the value of the TextureName property in the Dependency Property PropertyChanged handler:
public static readonly DependencyProperty TextureNameProperty =
DependencyProperty.Register("TextureName", typeof(string), typeof(TextureEditor),
// on property changed delegate: (DependencyObject, DependencyPropertyChangedEventArgs)
new PropertyMetadata((obj, args) => {
// update the target property using the new value
(obj as TextureEditor).TextureName = args.NewValue as string;
})
);
when I run this code the Item-object in my CustomControl becomes a System.Windows.Data.Binding containing nothing but null values but the DataContext becomes an MyClass object (which Items is populated with)
<UserControl x:Name="thisControl">
<Grid x:Name="LayoutRoot">
<ItemsControl ItemsSource="{Binding ElementName=thisControl,Path=Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:UniformGrid Columns="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CustomControl Item="{Binding}" DataContext="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
My CustomControl class
public partial class CustomControl : UserControl
{
public CustomControl()
{
InitializeComponent();
}
public object Item { get; set; }
}
is there something i don't know about ItemsControl?
this is written in Silverlight 4.0
Thanks in advance!
There is no need for you to be attempting to assign the custom control DataContext. The ItemsControl will take care of that for you.
Also your CustomControl code needs to specify the Item property as a DependencyProperty for the binding to work. Binding doesn't work on plain ordinary properties.
Example:
public object Item
{
get { return GetValue(ItemProperty); }
set { SetValue(ItemProperty, value); }
}
public static readonly DependencyProperty ItemProperty =
DependencyProperty.Register(
"Item",
typeof(object),
typeof(CustomControl),
new PropertyMetadata(null))
(I assume that RSListBoxStopItem is a typo and you meant to generalise to CustomControl)
I have the following ViewModel and I'd like to bind the HotkeysForeground to change the color in the ListBox.
namespace Monkey.Core.ViewModel
{
using System;
using System.Collections.ObjectModel;
using System.Windows.Media;
using Monkey.Core.SystemMonitor.Accessibility;
using Monkey.Core.SystemMonitor.Input;
public class MainWindowViewModel : WorkspaceViewModel
{
private readonly FocusManager _focusManager;
private readonly HotkeyManager _hotkeyManager;
private readonly ObservableCollection<string> _hotkeys;
private Brush _foregroundColor;
private string _title;
public MainWindowViewModel()
{
_hotkeys = new ObservableCollection<string>();
_hotkeyManager = new HotkeyManager();
_hotkeyManager.NewHotkey += HotkeyManager_NewHotkey;
_focusManager = new FocusManager();
_focusManager.Focus += FocusManager_Focus;
}
public Brush HotkeysForeground
{
get
{
return _foregroundColor;
}
set
{
_foregroundColor = value;
OnPropertyChanged(() => Title);
}
}
public ReadOnlyObservableCollection<string> Hotkeys
{
get
{
return new ReadOnlyObservableCollection<string>(_hotkeys);
}
}
public string Title
{
get
{
return _title;
}
set
{
_title = value;
OnPropertyChanged(() => Title);
}
}
protected override void OnDispose()
{
base.OnDispose();
_hotkeyManager.Dispose();
_focusManager.Dispose();
}
private void FocusManager_Focus(object sender, FocusManagerEventArgs e)
{
Title = e.Title;
}
private void HotkeyManager_NewHotkey(object sender, EventArgs eventArgs)
{
HotkeysForeground = Brushes.Blue;
_hotkeys.Clear();
foreach (var hotkey in _hotkeyManager.GetHotkeys())
{
_hotkeys.Add(hotkey);
}
}
}
}
I want to change the foreground color of the items in the ListBox every time the "HotkeyManager_NewHotkey" is fired, to some reason I can't seems to bind it to the view, I tried multiple things to make it work to no avail.
Here is the View I have.
<Window x:Class="Monkey.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="{Binding Mode=OneWay, Path=Title, UpdateSourceTrigger=PropertyChanged}" Height="200" Width="200" ShowInTaskbar="False" WindowStyle="ToolWindow" Topmost="True" ResizeMode="CanResizeWithGrip" AllowsTransparency="False">
<ListBox
Canvas.Left="110"
Canvas.Top="74"
Name="HotkeyList"
Height="Auto" Width="Auto" HorizontalContentAlignment="Left"
BorderThickness="0"
ScrollViewer.CanContentScroll="False"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ItemsSource="{Binding Path=Hotkeys}" VerticalAlignment="Stretch" VerticalContentAlignment="Center" FontSize="20">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Window>
I'm fairly new to WPF and haven't really explored bindings into depth so any help is appreciated.
For starters, you're notifying about Title property change in HotkeysForeground. However, this might not be the case.
If fixing that doesn't help, this rather lenghty way should work for you:
change HotkeysForeground property type to string (just store color name)
create static resource brush in XAML, bind it to color name
override listbox item template to something fairly simple (eg. Label) and bind its foreground to previously mentioned bursh
So, applying those changes:
public string HotkeysForeground
{
get { return _foregroundColor; }
set
{
_foregroundColor = value;
// I assume this is some smart workaround to INPC...
OnPropertyChanged(() => HotkeysForeground);
}
}
Now, in XAML you'll have to do this:
<!-- need to import System namespace -->
<Window x:Class="Monkey.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Window.Resources>
<SolidColorBrush Color="{Binding HotkeysForeground}" x:Key="HotkeysBrush"/>
</Window.Resources>
<ListBox ItemsSource="{Binding Path=Hotkeys}">
<ListBox.ItemTemplate>
<!
<DataTemplate DataType="{x:Type sys:String}">
<Label Content="{Binding}"
Foreground="{StaticResource HotkeysBrush}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
I needed to build a custom treeview as a user control. I called it for the sake of the example TreeViewEx :
<UserControl x:Class="WpfApplication4.TreeViewEx"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root">
<Grid>
<TreeView ItemsSource="{Binding Path=ItemsSource, ElementName=root}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Node : "/>
<ContentControl Content="{Binding Path=AdditionalContent, ElementName=root}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</UserControl>
The idea is to have a fixed part of the content of the ItemTemplate and a customizable part of it.
Of course, I created two dependency properties on the TreeViewEx class :
public partial class TreeViewEx
{
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
"ItemsSource", typeof(IEnumerable), typeof(TreeViewEx));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty AdditionalContentProperty = DependencyProperty.Register(
"AdditionalContent", typeof(object), typeof(TreeViewEx));
public object AdditionalContent
{
get { return GetValue(AdditionalContentProperty); }
set { SetValue(AdditionalContentProperty, value); }
}
public TreeViewEx()
{
InitializeComponent();
}
}
Having a simple node class like so :
public class Node
{
public string Name { get; set; }
public int Size { get; set; }
public IEnumerable<Node> Children { get; set; }
}
I would feed the treeview. I place an instance of TreeViewEx on the MainWindow of a WPF test project :
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication4">
<Grid>
<local:TreeViewEx x:Name="tree">
<local:TreeViewEx.AdditionalContent>
<TextBlock Text="{Binding Name}"/>
</local:TreeViewEx.AdditionalContent>
</local:TreeViewEx>
</Grid>
</Window>
And finally feed it :
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
var dummyData = new ObservableCollection<Node>
{
new Node
{
Name = "Root",
Size = 3,
Children = new ObservableCollection<Node>
{
new Node{
Name="Child1",
Size=2,
Children = new ObservableCollection<Node>{
new Node{
Name = "Subchild",
Size = 1
}
}
}
}
}
};
tree.ItemsSource = dummyData;
}
}
However it doesn't work as expected namely at first the ContentControl has the data but as I expand the nodes it does not display the ContentControl's content.
I don't really get it.. I should use a DataTemplate or something else?
The problem is that you're setting the content to an instance of a control, and that control can only have one parent. When you expand the tree and it adds it to the second node, it removes it from the first one.
As you suspected, you want to supply a DataTemplate to TreeViewEx instead of a control. You can use a ContentPresenter to instantiate the template at each level of the tree:
Replace the AdditionalContentProperty with:
public static readonly DependencyProperty AdditionalContentTemplateProperty = DependencyProperty.Register(
"AdditionalContentTemplate", typeof(DataTemplate), typeof(TreeViewEx));
public DataTemplate AdditionalContentTemplate
{
get { return (DataTemplate)GetValue(AdditionalContentTemplateProperty); }
set { SetValue(AdditionalContentTemplateProperty, value); }
}
change the HierarchicalDataTemplate in your UserControl's XAML to:
<StackPanel Orientation="Horizontal">
<TextBlock Text="Node : "/>
<ContentPresenter ContentTemplate="{Binding Path=AdditionalContentTemplate, ElementName=root}"/>
</StackPanel>
and change MainWindow to:
<local:TreeViewEx x:Name="tree">
<local:TreeViewEx.AdditionalContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</local:TreeViewEx.AdditionalContentTemplate>
</local:TreeViewEx>
This should be a very simple case, but I am pulling hair trying to get it to work. Here is the setup:
I am designing an app that will have an read-only mode and edit mode for some data. So I created a User Control which is a textbox and textblock bound to the same text data and are conditionally visible based on EditableMode property (so when it's editable the textbox is shown and when it's not the textblock is shown)
Now, I want to have many of these controls in my main window and have them all bound too a single bool property. When that property is changed via a button, I want all TextBlocks to turn into TextBoxes or back.
My problem is that the control is set correctly on binding, and if I do myUserControl.Editable = true. But it doesn't change if bind it to a bool property.
Here is the code for my user control:
<UserControl x:Class="CustomerCareTool.Controls.EditableLabelControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:CustomerCareTool.Converters"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<UserControl.Resources>
<src:BoolToVisibility x:Key="boolToVisibility" Inverted="False" />
<src:BoolToVisibility x:Key="invertedBoolToVisibility" Inverted="True" />
</UserControl.Resources>
<Grid>
<TextBlock Name="textBlock" Text="{Binding Path=TextBoxValue}" Visibility="{Binding Path=EditableMode, Converter={StaticResource invertedBoolToVisibility}}"/>
<TextBox Name="textBox" Visibility="{Binding Path=EditableMode, Converter={StaticResource boolToVisibility}}">
<TextBox.Text>
<Binding Path="TextBoxValue" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
</Grid>
I used a converter to convert bool to visibility and inverse bool to visibility. Not sure if that's at all needed here.
And this is the code behind:
public partial class EditableLabelControl : UserControl
{
public EditableLabelControl()
{
InitializeComponent();
}
public string TextBoxValue
{
get { return (string)GetValue(TextBoxValueProperty); }
set { SetValue(TextBoxValueProperty, value); }
}
public static readonly DependencyProperty TextBoxValueProperty =
DependencyProperty.Register("TextBoxValue", typeof(string), typeof(EditableLabelControl), new UIPropertyMetadata());
public bool EditableMode
{
get { return (bool)GetValue(EditableModeProperty); }
set { SetValue(EditableModeProperty, value); }
}
public static readonly DependencyProperty EditableModeProperty =
DependencyProperty.Register("EditableMode", typeof(bool),typeof(EditableLabelControl), new UIPropertyMetadata(false, EditableModePropertyCallBack));
static void EditableModePropertyCallBack(DependencyObject property,
DependencyPropertyChangedEventArgs args)
{
var editableLabelControl = (EditableLabelControl)property;
var editMode = (bool)args.NewValue;
if (editMode)
{
editableLabelControl.textBox.Visibility = Visibility.Visible;
editableLabelControl.textBlock.Visibility = Visibility.Collapsed;
}
else
{
editableLabelControl.textBox.Visibility = Visibility.Collapsed;
editableLabelControl.textBlock.Visibility = Visibility.Visible;
}
}
}
Now in my main application I have the control added like this:
<Controls:EditableLabelControl x:Name="testCtrl" EditableMode="{Binding Path=Editable}" TextBoxValue="John Smith" Grid.Row="0"/>
For that same application the DataContext is set to self
DataContext="{Binding RelativeSource={RelativeSource Self}}"
And the code behind looks like this:
public partial class OrderInfoView : Window, INotifyPropertyChanged
{
public OrderInfoView()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Editable = !Editable;
}
private bool _editable = false;
public bool Editable
{
get
{
return _editable;
}
set
{
_editable = value;
OnPropertyChanged("Editable");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged == null) return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Clicking the button doesn't do anything :( I tried everything to get this to work, and no dice. Would really appreciate some help!
I tried the following, and still does not work:
public bool Editable
{
get { return (bool)GetValue(EditableProperty); }
set { SetValue(EditableProperty, value); }
}
public static readonly DependencyProperty EditableProperty =
DependencyProperty.Register("Editable", typeof(bool), typeof(OrderInfoView), new UIPropertyMetadata(false));
It looks like your solution may be more complex than necessary. If all you want to do is have a disabled TextBox look like a TextBlock then you can do this using a trigger and a template. Then you can apply that style to all text boxes.
Here's an example of that approach:
<Window x:Class="WpfApplication25.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
>
<Window.Resources>
<!-- Disable TextBox Style -->
<Style x:Key="_DisableTextBoxStyle" TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<!--
Be sure to apply all necessary TemplateBindings between
the TextBox and TextBlock template.
-->
<TextBlock Text="{TemplateBinding Text}"
FontFamily="{TemplateBinding FontFamily}"
/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox IsEnabled="{Binding IsChecked, ElementName=uiIsEnabled}"
Style="{StaticResource _DisableTextBoxStyle}"
/>
<ToggleButton x:Name="uiIsEnabled" Content="Enable" IsChecked="True" />
</StackPanel>
</Window>
INotifyPropertyChanged does not work for classes that derive from DependencyObject.
Editable property in OrderInfoView must be dependency property in order for binding to work correctly, although technically your code is correct but I feel its bug in WPF that when object is dependency object it ignores INotifyPropertyChanged event because it is searching for notification in property system.
<Controls:EditableLabelControl x:Name="testCtrl"
EditableMode="{Binding Path=Editable,ElementName=userControl}" TextBoxValue="John Smith" Grid.Row="0"/>
Specify ElementName in binding tag and also name your usercontrol with x:FieldName or x:Name
I just came across this searching for something else.
Without reading your post in detail (no time atm sorry) it seems to me you're having a similar issue to the one I posted about here:
http://jonsblogat.blogspot.com/2009/11/wpf-windowdatacontext-and.html
In short, move your binding for your main window to the Grid and use a relative binding to see if that fixes your problem.