Reputation: 4443
I have TreeView
control and I want to bind tree nodes' IsExpanded
property to my DataSource
items!
But I have an exception:
System.Windows.Markup.XamlParseException occurred
Message=Set property '' threw an exception.
StackTrace:
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at SilverlightTree.BSTreeView.InitializeComponent()
at SilverlightTree.BSTreeView..ctor()
InnerException: System.NotSupportedException
Message=Cannot set read-only property ''.
StackTrace:
at MS.Internal.XamlMemberInfo.SetValue(Object target, Object value)
at MS.Internal.XamlManagedRuntimeRPInvokes.SetValue(XamlTypeToken inType, XamlQualifiedObject& inObj, XamlPropertyToken inProperty, XamlQualifiedObject& inValue)
InnerException:
inner exception:
{System.NotSupportedException: Cannot set read-only property ''.
XAML:
<Grid x:Name="LayoutRoot">
<controls:TreeView Name="treeView" SelectedItemChanged="treeView_SelectedItemChanged"
Style="{Binding TreeViewConnectingLines}" BorderBrush="{x:Null}">
<controls:TreeView.ItemTemplate>
<toolkit:HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" Background="Transparent">
<toolkitDrag:ContextMenuService.ContextMenu>
<toolkitDrag:ContextMenu Loaded="ContextMenu_Loaded"
Opened="ContextMenu_Opened"/>
</toolkitDrag:ContextMenuService.ContextMenu>
<Image Source="{Binding Path=Type.Icon}" Width="20" Height="20" />
<TextBlock Text="{Binding Path=FullDescription}" Height="20"
TextAlignment="Center" HorizontalAlignment="Center" />
</StackPanel>
</toolkit:HierarchicalDataTemplate>
</controls:TreeView.ItemTemplate>
<controls:TreeView.ItemContainerStyle>
<Style TargetType="controls:TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded}"></Setter>
</Style>
</controls:TreeView.ItemContainerStyle>
</controls:TreeView>
</Grid>
and the data items:
public interface INode
{
NodeType Type { get; set; }
bool IsSelected { get; set; }
bool IsExpanded { get; set; }
List<INode> Children{get;set;};
}
Upvotes: 9
Views: 3232
Reputation: 48959
If you are using SL5 then the standard XAML setters should work. But, if you are using SL4 or below then you will need to use SetterValueBindingHelper
from here. Then your XAML will look like the following. Make sure you carefully copy what I have below.
<sdk:TreeView.ItemContainerStyle>
<Style TargetType="sdk:TreeViewItem">
<Setter Property="local:SetterValueBindingHelper.PropertyBinding">
<Setter.Value>
<local:SetterValueBindingHelper>
<local:SetterValueBindingHelper Property="IsSelected" Binding="{Binding Mode=TwoWay, Path=IsSelected}"/>
<local:SetterValueBindingHelper Property="IsExpanded" Binding="{Binding Mode=TwoWay, Path=IsExpanded}"/>
</local:SetterValueBindingHelper>
</Setter.Value>
</Setter>
</Style>
</sdk:TreeView.ItemContainerStyle>
The syntax isn't exactly like what you would use in WPF, but it works and it works well!
Upvotes: 1
Reputation: 1240
To follow up on Malcom, I got it to work using the ItemContainerStyle instead with SL5.
<sdk:TreeView.ItemContainerStyle>
<Style TargetType="sdk:TreeViewItem">
<Setter Property="IsExpanded" Value="True"/>
<Setter Property="Visibility" Value="{Binding IsVisible, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
</Style>
</sdk:TreeView.ItemContainerStyle>
Upvotes: 1
Reputation: 4999
I just wanted to point out that this is now possible. I'm using Silverlight 5, along with Silverlight Toolkit compiled against SL5 and you can bind to IsExpanded. I did define the style in a slightly different place than you. Here is my XAML.
<controls:TreeView ItemsSource="{Binding Repository.MajorClasses}" ItemTemplate="{StaticResource TreeviewMajorClassTemplate}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<controls:TreeView.Resources>
<Style TargetType="controls:TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
</controls:TreeView.Resources>
</controls:TreeView>
In case you were wondering, the SelectedItem binding does give a warning (as it is still a readonly property of TreeView).
Didn't really want to bring up an old thread, but this was the most recent one I saw on this topic and felt it'd be useful for people to know it does in fact work.
Upvotes: 4
Reputation: 11297
The quickest way is to subclass both the TreeView
and the TreeViewItem
, for example:
public class BindableTreeViewItem : TreeViewItem
{
protected override DependencyObject GetContainerForItemOverride()
{
var itm = new BindableTreeViewItem();
itm.SetBinding(TreeViewItem.IsExpandedProperty, new Binding("IsExpanded") { Mode = BindingMode.TwoWay });
return itm;
}
}
public class BindableTreeView : TreeView
{
protected override DependencyObject GetContainerForItemOverride()
{
var itm = new BindableTreeViewItem();
itm.SetBinding(TreeViewItem.IsExpandedProperty, new Binding("IsExpanded") { Mode = BindingMode.TwoWay });
return itm;
}
}
Unfortunately you'll lose the default theming of the TreeView
when you do the subclassing. That is a weakness of the Silverlight theming concept. Thus you could alternatively use a custom Attached Property or a Behavior that traverses the tree and sets the bindings from outside. Because the tree nodes are created lazily on-demand though, you'd have to listen to the Expanded
event once for each node that has not yet been rendered, then set the bindings in that event handler for each of its children after waiting for the layout pass.
Upvotes: 6