Telerik RadTreeListView Event binding - silverlight

I am currently working on a Telerik Silverlight Control, the RadTreeListView.
Is it possible to bind a DoubleClick Event to this control? Please note that I'am using
MVVM pattern and that the RadTreeListView isn't equal to the RadTreeView control.
It would be nice if anyone can share his experience with me.
I tried many ways, but nothing worked..
Last example (look at the command):
<telerik:RadTreeListView x:Name="TreeListControl"
AutoGenerateColumns="False"
IsReadOnly="True"
ItemsSource="{Binding TreeViewData, ValidatesOnDataErrors=True}"
IsExpandedBinding="{Binding IsExpanded, Mode=TwoWay}"
CanUserFreezeColumns="False"
RowIndicatorVisibility="Collapsed"
ColumnWidth="*"
CanUserSortColumns="False"
evt:MouseDoubleClick.Command="{Binding DoubleCommand}"
>
Helper Class:
.... public static class MouseDoubleClick
{
public static DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command",
typeof(ICommand),
typeof(MouseDoubleClick),
new PropertyMetadata(CommandChanged));
public static DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached("CommandParameter",
typeof(object),
typeof(MouseDoubleClick),
new PropertyMetadata(null)); ....
The compiler gives out the error:
Error 3 The property 'Command' does not exist on the type 'RadTreeListView' in the XML namespace 'clr-namespace:CombinationTreeViewControl'. C:\Users\B95703\Documents\Entwicklung\Silverlight\SilverlightComponents\CombinationTreeViewControl\View\CombinationTreeViewControl.xaml 32 34 CombinationTreeViewControl
Best regards
Patrik

Instead of using PropertyMetaData in your RegisteredAttached() methods, try using UIPropertyMetaData.
Also see my answer here:
https://stackoverflow.com/a/13886760/430897

Try using System.Windows.Interactivity Triggers on your TreeListView on the Click event:
<i:Interaction.Triggers><i:EventTrigger EventName="DoubleClick">
<i:InvokeCommandAction Command="{Binding DataContext.TreeViewDoubleClickCommand, ElementName=LayoutRoot}"
CommandParameter="{Binding SelectedItem,ElementName=MyTreeView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Considering that the DoubleClick event is exposed in the TreeListView control.

you can use of RowsIsexpandedChange.when expanding changing, you can use of variable isexpand.
private ICommand _rowIsExpandedChangedClick;
public ICommand RowIsExpandedChangedClick
{
get
{
if (_rowIsExpandedChangedClick == null)
{
_rowIsExpandedChangedClick = new MVVM.DelegateCommand<Telerik.Windows.Controls.GridView.RowEventArgs>(RowIsExpandedChangedClickShow);
}
return _rowIsExpandedChangedClick;
}
set { _rowIsExpandedChangedClick = value; }
}
RadTreeListView _currentRadTreeListView;
private void RowIsExpandedChangedClickShow(Telerik.Windows.Controls.GridView.RowEventArgs e)
{
var folder = e.Row.DataContext as YourClass;
var row = e.Row as GridViewRow;
_currentRadTreeListView = e.OriginalSource as RadTreeListView;
if (row.IsExpanded)
{
folder.Isexpanded = row.IsExpanded;
}
}
//----------------------------------------ExpandHierarchyItem for expand specialitems
private void collapseorexpand(FolderSarfasl _currntfolder)
{
if(_currntfolder.Isexpanded==true)
if(_currentRadTreeListView!=null)
_currentRadTreeListView.ExpandHierarchyItem(_currntfolder);
for (int i = 0; i < _currntfolder.SubFolders.Count; i++)
{
collapseorexpand(_currntfolder.SubFolders[i]);
}
}

Related

Property bound to DependencyProperty won't update despite TwoWay Binding set

I have a little problem here. I've created custom TreeView using RadTreeView. It all works nice, but I've encountered an obstacle. I've set DependencyProperty for SelectedItem in TreeView. I nest my control in View, bind property to SelectedItem in TwoWay mode, but bound property won't update, it's null all the time, despite DependencyProperty value being set.
Here's tree xaml:
<Grid xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:sdk='http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk'
xmlns:telerik='http://schemas.telerik.com/2008/xaml/presentation' x:Name='this' >
<Grid.Resources>
<DataTemplate x:Key='ChildTemplate'>
<TextBlock Text='{Binding Path=ChildPath}' Margin='5,0' />
</DataTemplate>
<telerik:HierarchicalDataTemplate x:Key='NameTemplate' ItemsSource='{Binding ChildrenCollectionPath}' ItemTemplate='{StaticResource ChildTemplate}'>
<TextBlock Text='{Binding Path=ParentPath }' Padding='7'/>
</telerik:HierarchicalDataTemplate>
</Grid.Resources>
<telerik:RadTreeView x:Name='rtvTreeView' Padding='5' BorderThickness='0' IsEditable='False' IsLineEnabled='True' IsExpandOnDblClickEnabled='False' ItemTemplate='{StaticResource NameTemplate}' />
</Grid>
Below is way I nest the control in View:
<windows:TreeViewReuse CollectionSource="{Binding SitesCollectionWithAddress}" ParentPath="Napis" Grid.Column="0" BorderThickness="2" SelectedItemD="{Binding SelectedSide, ElementName=this, UpdateSourceTrigger=Explicit, Mode=TwoWay}" ChildPath="FullAddress" ChildrenCollectionPath="AdresyStrony" BorderBrush="Red" DoubleClickCommand="{Binding TreeViewDoubleClick}">
</windows:TreeViewReuse>
And here's Tree's code behind in parts:
public partial class TreeViewReuse : UserControl
{
static Telerik.Windows.FrameworkPropertyMetadata propertyMetaData = new Telerik.Windows.FrameworkPropertyMetadata(null,
Telerik.Windows.FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(SelectedItemChangedCallback));
public object SelectedItemD
{
get { return GetValue(SelectedItemDProperty); }
set { SetValue(SelectedItemDProperty, value); }
}
public static readonly DependencyProperty SelectedItemDProperty =
DependencyProperty.Register("SelectedItemD", typeof(object), typeof(TreeViewReuse), propertyMetaData);
public TreeViewReuse()
{
InitializeComponent();
Loaded += new RoutedEventHandler(TreeViewReuse_Loaded);
}
void treeView_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
{
SelectedItemD = _treeView.SelectedItem;
}
static private void SelectedItemChangedCallback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
}
Does anyone have an idea why property bound to SelectedItemD does not update? I don't care about setting tree's selected item from it, I only want to set it to selected item.
Here's property:
public StronaSprawy SelectedSide
{
get
{
return _selectedSide;
}
set
{
_selectedSide = value;
}
}
Your Dependency Property looks fine.. all except for that Telerik.Windows.FrameworkPropertyMetadata instance.
Silverlight does not support setting meta data options, so I cant think how the Telerik implementation will achieve that. It is possible that Telerik have their own DP implementation, or even that this type of property meta data only works with their controls.
Try using the standard System.Windows.PropertyMetaData type instead and see if that works for you.

Bind TextBox.TextProperty to a property of type Binding from the Model

I've got a list of command buttons (with input) I want to bind with the model.
The thing is I want the textbox in the button to bind to somewhere (see viewmodel).
The following code is what I tried and failed. Is it (even) possible to set binding on the model then bind this to a control?
Or in other words am I trying to do something the stupid way?
View:
<ToolBar Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="0" ItemsSource="{Binding SelectedTab.Commands}" Height="34">
<ToolBar.Resources>
<DataTemplate DataType="{x:Type model:ZoekCommandButtons}">
<Button Command="{Binding Command}" ToolTip="{Binding Tooltip}" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image, Converter={StaticResource ImageConv}}" Height="16" Width="16"></Image>
**<TextBox Width="100" Text="{Binding Text}">**
<TextBox.InputBindings>
<KeyBinding Gesture="Enter" Command="{Binding Command}"></KeyBinding>
</TextBox.InputBindings>
</TextBox>
</StackPanel>
</Button>
</DataTemplate>
</ToolBar.Resources>
</ToolBar>
Model:
public class ZoekCommandButtons : BaseModel, ICommandItem
{
private string _header;
private string _image;
private bool _isEnabled;
private Visibility _isVisible;
private ICommand _command;
private string _tooltip;
private Binding _text;
public Binding Text
{
get { return _text; }
set { _text = value; OnPropertyChanged("Text"); }
}
(etc)
Viewmodel:
Commands.Add(new ZoekCommandButtons()
{
Image = "search.png",
IsEnabled = true,
**Text = new Binding { RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(UserControl), 1), Path = new PropertyPath("FilterText") },**
Command = FilterCommand,
Tooltip = "Zoeken",
Header = "Zoeken"
});
First off, I would not recommend exposing Binding as a ViewModel property; in this particular case, it sounds more to me like you have nested ViewModels, and that approach would be far more suitable - that is, you have a "MamaViewModel" that has your "Commands" property, which is in turn a collection of "CommandButtonViewModels"...
Ok, That said...you can do this, although I must reiterate that you probably should not; what you're missing is "something to evaluate the Binding on" to provide a value. Here's a class that gives you that:
public static class BindingEvaluator
{
// need a DP to set the binding to
private static readonly DependencyProperty PlaceholderProperty =
DependencyProperty.RegisterAttached("Placeholder", typeof(object), typeof(DependencyObject), new UIPropertyMetadata(null));
// Evaluate a binding by attaching it to a dummy object/property and evaluating the property value
public static object Evaluate(Binding binding)
{
var throwaway = new DependencyObject();
BindingOperations.SetBinding(throwaway, PlaceholderProperty, binding);
var retVal = throwaway.GetValue(PlaceholderProperty);
return retVal;
}
}
That, combined with a ViewModel definition something like:
public class DontDoThisViewModel
{
public Binding TextBinding {get; set;}
public string Text
{
get
{
return BindingEvaluator.Evaluate(TextBinding) as string;
}
}
}
Should work...here's a test app I threw together in LINQPad:
void Main()
{
var wnd = new Window() { Title = "My window" };
var text = new TextBlock();
text.Text = "Hopefully this shows the window title...";
text.SetBinding(TextBlock.TextProperty, new Binding("Text"));
wnd.Content = text;
var vm = new ViewModel();
var vmBinding = new Binding("Title");
vmBinding.Source = wnd;
vm.TextBinding = vmBinding;
wnd.DataContext = vm;
wnd.Show();
}
AGAIN, I must strongly recommend you NOT do this...but I was curious, so I had to come up with a way. ;)
Ok. I wasn't thinking straight.
Changed the Text property in the Model to string and handled the command with this property.
(although it would be nice to set binding on the model somehow...)

Executing viewmodels command on enter in TextBox

I want to execute a command in my viewmodel when the user presses enter in a TextBox.
The command works when bound to a button.
<Button Content="Add" Command="{Binding Path=AddCommand}" />
But I can't bring it to work from the TextBox.
I tried an Inputbinding, but it didn't work.
<TextBox.InputBindings>
<KeyBinding Command="{Binding Path=AddCommand}" Key="Enter"/>
</TextBox.InputBindings>
I also tried to set the working button as default, but it doesn't get executed when enter is pressed.
Thanks for your help.
I know I am late to the party, but I got this to work for me. Try using Key="Return" instead of Key="Enter"
Here is the full example
<TextBox Text="{Binding FieldThatIAmBindingToo, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Command="{Binding AddCommand}" Key="Return" />
</TextBox.InputBindings>
</TextBox>
Make sure to use UpdateSourceTrigger=PropertyChanged in your binding, otherwise the property will not be updated until focus is lost, and pressing enter will not lose focus...
Hope this was helpful!
You have probably not made the command a property, but a field. It only works to bind to properties. Change your AddCommand to a property and it will work. (Your XAML works fine for me with a property instead of a field for the command -> no need for any code behind!)
Here's an attached dependency property I created for this. It has the advantage of ensuring that your text binding is updated back to the ViewModel before the command fires (useful for silverlight which doesn't support the property changed update source trigger).
public static class EnterKeyHelpers
{
public static ICommand GetEnterKeyCommand(DependencyObject target)
{
return (ICommand)target.GetValue(EnterKeyCommandProperty);
}
public static void SetEnterKeyCommand(DependencyObject target, ICommand value)
{
target.SetValue(EnterKeyCommandProperty, value);
}
public static readonly DependencyProperty EnterKeyCommandProperty =
DependencyProperty.RegisterAttached(
"EnterKeyCommand",
typeof(ICommand),
typeof(EnterKeyHelpers),
new PropertyMetadata(null, OnEnterKeyCommandChanged));
static void OnEnterKeyCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
ICommand command = (ICommand)e.NewValue;
FrameworkElement fe = (FrameworkElement)target;
Control control = (Control)target;
control.KeyDown += (s, args) =>
{
if (args.Key == Key.Enter)
{
// make sure the textbox binding updates its source first
BindingExpression b = control.GetBindingExpression(TextBox.TextProperty);
if (b != null)
{
b.UpdateSource();
}
command.Execute(null);
}
};
}
}
You use it like this:
<TextBox
Text="{Binding Answer, Mode=TwoWay}"
my:EnterKeyHelpers.EnterKeyCommand="{Binding SubmitAnswerCommand}"/>
You need to define Gesture instead of Key property of the KeyBinding:
<TextBox.InputBindings>
<KeyBinding Gesture="Enter" Command="{Binding AddCommand}"/>
</TextBox.InputBindings>
In addition to Mark Heath's answer, I took the class one step further by implementing Command Parameter attached property in this way;
public static class EnterKeyHelpers
{
public static ICommand GetEnterKeyCommand(DependencyObject target)
{
return (ICommand)target.GetValue(EnterKeyCommandProperty);
}
public static void SetEnterKeyCommand(DependencyObject target, ICommand value)
{
target.SetValue(EnterKeyCommandProperty, value);
}
public static readonly DependencyProperty EnterKeyCommandProperty =
DependencyProperty.RegisterAttached(
"EnterKeyCommand",
typeof(ICommand),
typeof(EnterKeyHelpers),
new PropertyMetadata(null, OnEnterKeyCommandChanged));
public static object GetEnterKeyCommandParam(DependencyObject target)
{
return (object)target.GetValue(EnterKeyCommandParamProperty);
}
public static void SetEnterKeyCommandParam(DependencyObject target, object value)
{
target.SetValue(EnterKeyCommandParamProperty, value);
}
public static readonly DependencyProperty EnterKeyCommandParamProperty =
DependencyProperty.RegisterAttached(
"EnterKeyCommandParam",
typeof(object),
typeof(EnterKeyHelpers),
new PropertyMetadata(null));
static void OnEnterKeyCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
ICommand command = (ICommand)e.NewValue;
Control control = (Control)target;
control.KeyDown += (s, args) =>
{
if (args.Key == Key.Enter)
{
// make sure the textbox binding updates its source first
BindingExpression b = control.GetBindingExpression(TextBox.TextProperty);
if (b != null)
{
b.UpdateSource();
}
object commandParameter = GetEnterKeyCommandParam(target);
command.Execute(commandParameter);
}
};
}
}
Usage:
<TextBox Text="{Binding Answer, Mode=TwoWay}"
my:EnterKeyHelpers.EnterKeyCommand="{Binding SubmitAnswerCommand}"
my:EnterKeyHelpers.EnterKeyCommandParam="your parameter"/>

Assign binding path at runtime in WPF DataTemplate

I am writing a WPF program in C# in which I have a ListView for which the columns will be populated at runtime. I would like to use a custom DataTemplate for the GridViewColumn objects in the ListView.
In the examples I have seen where the number of columns is fixed in advance, a custom DataTemplate is often created using something like the XAML below.
<DataTemplate x:Key="someKey">
<TextBlock Text="{Binding Path=FirstName}" />
</DataTemplate>
This DataTemplate could also later be assigned to GridViewColumn.CellTemplate in the code-behind by calling FindResource("someKey"). However, this alone is of no use to me, because in this example the Path element is fixed to FirstName. Really I need something where I can set the Path in code.
It is my impression that something along these lines may be possible if XamlReader is used, but I'm not sure how in practice I would do this. Any solutions are greatly appreciated.
It is easy to build what you need using two DataTemplates working in concert: The outer DataTemplate simply sets the DataContext for the inner DataTemplate, as follows:
<DataTemplate x:Key="DisplayTemplate">
<Border ...>
<TextBlock Text="{Binding}" ... />
</Border>
</DataTemplate>
<DataTemplate x:Key="CellTemplate">
<ContentPresenter Content="{Binding FirstName}"
ContentTemplate="{StaticResource DisplayTemplate}" />
</DataTemplate>
The only tricky thing is making it convenient to set this on a GridViewColumn. I would accomplish this with attached properties, allowing you to write:
<GridViewColumn
my:GVCHelper.DisplayPath="FirstName"
my:GVCHelper.Template="{StaticResource DisplayTemplate}" />
Or equivalently in code:
var col = new GridViewColumn();
GVCHelper.SetDisplayPath(col, "FirstName");
GVCHelper.SetTemplate(col, (DataTemplate)FindResource("DisplayTemplate"));
Either of these would cause the DataTemplate named "DisplayTemplate" to be used to display the FirstName in the column.
The helper class would be implemented as:
public class GVCHelper : DependencyObject
{
public static string GetDisplayPath(DependencyObject obj) { return (string)obj.GetValue(DisplayPathProperty); }
public static void SetDisplayPath(DependencyObject obj, string value) { obj.SetValue(DisplayPathProperty, value); }
public static readonly DependencyProperty DisplayPathProperty = DependencyProperty.RegisterAttached("DisplayPath", typeof(string), typeof(GVCHelper), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) => Update(obj)
});
public static DataTemplate GetTemplate(DependencyObject obj) { return (DataTemplate)obj.GetValue(TemplateProperty); }
public static void SetTemplate(DependencyObject obj, DataTemplate value) { obj.SetValue(TemplateProperty, value); }
public static readonly DependencyProperty TemplateProperty = DependencyProperty.RegisterAttached("Template", typeof(DataTemplate), typeof(GVCHelper), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) => Update(obj)
});
private static void Update(DependencyObject obj)
{
var path = GetDisplayPath(obj);
var template = GetTemplate(obj);
if(path!=null && template!=null)
{
var factory = new FrameworkElementFactory(typeof(ContentPresenter));
factory.SetBinding(ContentPresenter.ContentProperty, new Binding(path));
factory.SetValue(ContentPresenter.ContentTemplateProperty, template);
obj.SetValue(GridViewColumn.CellTemplateProperty,
new DataTemplate { VisualTree = factory };
}
}
}
How it works: Whenever the properties are both set, a new DataTemplate is constructed and the GridViewColumn.CellTemplate property is updated.
Maybe GridViewColumn.CellTemplateSelector would help you? Or you could create a user control, bind it to something big enough (that's the same for each column). Then let this control figure out what exactly it should display based on what it has in DataContext...

Problem databinding a custom control in silverlight

I'm attempting to databind a custom control in Silverlight 3 and I'm getting strange problems with it.
My xaml for the user control is this:
<UserControl x:Class="StronicoMain.GenericSmallIcon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300" >
<Canvas x:Name="canGSI">
</Canvas>
</UserControl>
The codebehind for the user control is this
private string _EntityTypeID;
public string EntityTypeID
{
get
{
return _EntityTypeID;
}
set
{
_EntityTypeID = value;
}
}
public GenericSmallIcon()
{
InitializeComponent();
Loaded += new RoutedEventHandler(Page_Loaded);
}
public void Page_Loaded(object sender, RoutedEventArgs e)
{
icoMale icoMale = new icoMale();
icoFemale icoFem = new icoFemale();
if (EntityTypeID == null)
{
canGSI.Children.Add(icoMale);
}
else if (EntityTypeID == "1")
{
canGSI.Children.Add(icoMale);
}
else if (EntityTypeID == "2")
{
canGSI.Children.Add(icoFem);
}
else
{
canGSI.Children.Add(icoMale);
}
}
I'm calling it from the DataGridSelection Adapter (taken from the Microsoft Toolkit example page for AutoCompleteBox-Datagrid version) - the relevant portion looks like this:
<Stron:DataGridSelectionAdapter x:Name="SelectionAdapter" AutoGenerateColumns="False" IsReadOnly="False">
<Stron:DataGridSelectionAdapter.Columns>
<data:DataGridTemplateColumn>
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate><Stron:GenericSmallIcon EntityTypeID="{Binding EntityTypeID}"></Stron:GenericSmallIcon></DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
<data:DataGridTextColumn Header="Contact Name" FontWeight="Bold" Foreground="#CC000000" Binding="{Binding EntityName}" />
<data:DataGridTextColumn Header="Tags" Binding="{Binding EntityTags}" />
</Stron:DataGridSelectionAdapter.Columns>
</Stron:DataGridSelectionAdapter>
I run the code, and I get the error "ManagedRuntimeError #4004" - if I try to use the custom control while manually setting the databinding it works just fine, if I try to rely on the values that are being databound I get the error. How can I create a custom databound event on a custom control? I think that is the problem, that the page is loading before the values are passed to it.
Thanks everyone.
~Steve
Update, here is the working, changed code as per the accepted answer
public static readonly DependencyProperty EntityTypeIDProperty = DependencyProperty.Register("EntityTypeID", typeof(string), typeof(GenericSmallIcon), new PropertyMetadata(new PropertyChangedCallback(GenericSmallIcon.OnEntityTypeIDPropertyChanged)));
public string EntityTypeID
{
get { return (string)GetValue(EntityTypeIDProperty); }
set { SetValue(EntityTypeIDProperty, value); }
}
private static void OnEntityTypeIDPropertyChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
GenericSmallIcon control = d as GenericSmallIcon;
string b = (string)e.NewValue;
}
This is invalid:
<Stron:GenericSmallIcon EntityTypeID="{Binding EntityTypeID}"/>
The problem is that you cannot bind to a Property that is not a Dependency Property. See this MSDN article about turning your POCO Property into a Dependency property.
-Mark

Resources