I have Windows Phone Class Library that uses the MVVM model. In my Generic.xaml I have the Style for my CustomElementControl.cs that has a CustomElementViewModel.cs. I also have a ViewModelLocator.cs that relates ViewModels to Controls that is named in this context as Locator, but that is not relevant to this case. Now, if I add a Command to a Button like so:
<Style TargetType="view:CustomElementControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="view:CustomElementControl">
<Page x:Name="pageRoot" DataContext="{Binding Source={StaticResource Locator}, Path=view:CustomElementViewModel, Mode=TwoWay}">
<TextBlock Text="something" Foreground="{Binding Path=ColorTest}" />
<Button Content="MyButton" Command="{Binding MultiSelectCommand}" />
</Page>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And catch in the CustomElementViewModel.cs like so:
private RelayCommand _multiSelectCommand;
public RelayCommand MultiSelectCommand {
get {
if(_multiSelectCommand == null) {
_multiSelectCommand = new RelayCommand(
() => {
this.SelectionMode = (this.SelectionMode == ListViewSelectionMode.Single) ? ListViewSelectionMode.Multiple : ListViewSelectionMode.Single;
});
}
return _multiSelectCommand;
}
}
It works fine, however, if I want to add the Command event to an AppBarButton like so:
<Style TargetType="viewCustomElementControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="view:CustomElementControl">
<Page x:Name="pageRoot" DataContext="{Binding Source={StaticResource Locator}, Path=view:CustomElementViewModel, Mode=TwoWay}">
<TextBlock Text="something" Foreground="{Binding Path=ColorTest}" />
</Page>
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Icon="AllApps" Label="multiselect" Command="{Binding MultiSelectCommand}" />
</CommandBar>
</Page.BottomAppBar>
</Page>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The RelayCommand is never triggered. What am I missing here?
UPDATE
I've even tried setting the DataContext of the AppBarButton like so:
<AppBarButton Icon="AllApps" Label="multiselect" Command="{Binding DataContext.MultiSelectCommand, ElementName=pageRoot, Mode=OneWay}" />
And
<AppBarButton Icon="AllApps" Label="multiselect" DataContext="{Binding Source={StaticResource Locator}, Path=CustomElementViewModel, Mode=TwoWay} Command="{Binding MultiSelectCommand}" />
And none works.
UPDATE 2
Here's a sample: http://1drv.ms/1vRnaYH
Related
In my C# WPF MVVM pattern application, I have an ItemsControl in my View that draws Lines and Buttons on a Canvas based on a bound ItemsSource, defined in XAML as below:
<Window.DataContext>
<viewmodels:MainWindowViewModel />
</Window.DataContext>
.
.
.
<ItemsControl
x:Name="DiagramViewCanvas"
ItemsSource="{Binding DiagramObjects, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:LineObject}">
<Line
X1="{Binding XStart}"
Y1="{Binding YStart}"
X2="{Binding XEnd}"
Y2="{Binding YEnd}"
Stroke="White"
StrokeThickness="1"
SnapsToDevicePixels="True"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ButtonObject}">
<Button
Style="{DynamicResource MyDiagramButtonStyle}"
Width="225"
Height="30"
Content="{Binding Content}"
FontSize="13"
SnapsToDevicePixels="True">
</Button>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Black" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding XPosition, UpdateSourceTrigger=PropertyChanged}" />
<Setter Property="Canvas.Top" Value="{Binding YPosition, UpdateSourceTrigger=PropertyChanged}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
This code works completely fine. My question is how to bind the Buttons' Click event to a method in the ViewModel (MainWindowViewModel).
Option 1 (which I don't want to use due MVVM pattern): If I try a simple Click event definition as below ...
<Button
Style="{DynamicResource MyDiagramButtonStyle}"
Width="225"
Height="30"
Content="{Binding Content}"
FontSize="13"
SnapsToDevicePixels="True"
Click="OnButtonClick"/>
... where OnButtonClick is defined in my XAML codebehind, the OnButtonClick method is successfully called and executed for each Button that is created at runtime. It works fine.
Option 2: However, if I try to use Interaction.Triggers as below (which is the approach I regularly use without any problems in my code) to avoid placing code in code behind ...
<Button
Style="{DynamicResource MyDiagramButtonStyle}"
Width="225"
Height="30"
Content="{Binding Content}"
FontSize="13"
SnapsToDevicePixels="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:CallMethodAction TargetObject="{Binding}" MethodName="OnButtonClick"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
... where OnButtonClick is defined in my MainWindowViewModel ...
public void OnButtonClick(object sender, RoutedEventArgs e)
{
if (sender is Button btn)
{
// do something
}
}
... I get the following error:
System.ArgumentException: 'Could not find method named 'OnButtonClick' on object of type 'ButtonObject' that matches the expected signature.'
Question 1: Am I making a basic mistake in my implementation of interaction triggers (I have many other interaction triggers in my code that work completely fine)? Or is it that Interaction.Triggers do not work in this scenario where the Buttons are created dynamically at runtime?
Question 2: Should I be using ICommand instead (for example as mentioned in Binding Commands to Events?)?
Thanks for any direction on what I am doing wrong.
Found a solution using Interaction.Triggers:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=DataContext}" MethodName="OnButtonClick"/>
</i:EventTrigger>
</i:Interaction.Triggers>
So, I have created a UserControl which really is an "advanced button".
I have implemented Dependency Properties, one of which is ICommand, that is supposed to be bindable further when control is used in an actual Window.
However, for some reason the Command doesn't work.
When I tried an exact same approach on a regular button, everything worked fine (thus it's not the fault of my DelegateCommand implementation or my ViewModel).
I tried to followup on why the bound command doesn't fire, but I couldn't find a reliable reason for it not to.
Here is my UserControl XAML:
<Window x:Class="NoContact.MainWindow"
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"
xmlns:local="clr-namespace:NoContact"
mc:Ignorable="d"
xmlns:userControls="clr-namespace:NoContact.UserControls"
Title="MainWindow" Height="800" Width="960" Background="#22282a">
<Border BorderThickness="1" BorderBrush="#ffcd22" Margin="10,10,10,10">
<Grid>
<Button HorizontalContentAlignment="Stretch" Foreground="{Binding ElementName=ImageButtonUC, Path=Foreground}"
Background="{Binding ElementName=ImageButtonUC, Path=Background}">
<DockPanel Width="{Binding ElementName=ImageButtonUC, Path=ActualWidth}">
<Image Source="{Binding ElementName=ImageButtonUC, Path=Image}" DockPanel.Dock="Left"
Height="{Binding ElementName=ImageButtonUC, Path=ActualHeight, Converter={StaticResource HeightConverter}}"
Width="{Binding ElementName=ImageButtonUC, Path=ActualWidth, Converter={StaticResource HeightConverter}}" VerticalAlignment="Center"/>
<TextBlock Text="{Binding ElementName=ImageButtonUC, Path=Text}" FontSize="17" VerticalAlignment="Center" />
</DockPanel>
</Button>
</Grid>
<UserControl.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
And here is my UserControl code-behind:
public partial class ImageButton : UserControl
{
// OTHER IRRELEVANT CLASS PARAMETERS ARE HERE
public ICommand ClickCommand
{
get { return (ICommand)GetValue(ClickCommandProperty); }
set { SetValue(ClickCommandProperty, value); }
}
// OTHER IRRELEVANT DEPENDENCY PROPERTIES ARE HERE
public static DependencyProperty ClickCommandProperty =
DependencyProperty.Register("ClickCommand", typeof(ICommand), typeof(ImageButton));
public ImageButton()
{
InitializeComponent();
}
}
Finally, this is how I use my control:
<userControls:ImageButton x:Name="phoneButton" ClickCommand="{Binding Path=MyButtonClickCommand}" Style="{StaticResource phoneImageButtonUCStyle}" Text="Telefon" Width="200" Height="100" VerticalAlignment="Top" />
The DataContext of the control is set on a stackpanel, that is wrapped around my control. I have also tried setting it directly on the control, no effect.
Again, doing the same on a regular button works just fine.
I have finally solved the problem - and it was pretty trivial.
I had ommited the most important binding - UserControl's button Command to UserControl's Dependency property.
Changing it like this made it work:
<Button HorizontalContentAlignment="Stretch" Foreground="{Binding ElementName=ImageButtonUC, Path=Foreground}"
Background="{Binding ElementName=ImageButtonUC, Path=Background}"
Command="{Binding ElementName=ImageButtonUC, Path=ClickCommand}">
I'm working in a Explorer tree view (custom wpf control designed by me). I have this code in Generic.xaml:
<Style TargetType="{x:Type local:ExplorerControl}">
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ExplorerControl}">
<Border>
<TreeView Name="myTreeView" >
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem x:Name="myTemplate" Header="Remove" Command="{TemplateBinding RemoveCommand}"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In ExplorerControl I have my Dependency Property:
public class ExplorerControl : Control{
public ExplorerControl()
{
Nodes = new ObservableCollection<Node>();
}
private ObservableCollection<Node> Nodes { get; }
public ICommand RemoveCommand
{
get { return (ICommand)GetValue(RemovedCommandProperty); }
set { SetValue(RemovedCommandProperty, value); }
}
public static readonly DependencyProperty RemovedCommandProperty =
DependencyProperty.Register("RemoveCommand", typeof(ICommand), typeof(ExplorerControl));
}
Node class
public class Node {
public string Name {get;set;}
}
My problem is that I don't know how to get that the MenuItem Command works
I have tried these:
If I use the same code with a button after the TreeView (with both in a Stackpanel) it works. So I think that the problem is the MenuItem DataContext
I tried to change the MenuItem DataContext however I didn't get it.
I hope you can help me.
Edit: I delete the part of code about DataContext. Thanks for you answers.
I use this control in my MainView:
<treeViewExplorerControl:ExplorerControl
SelectedItemName="{Binding SelectedItemName}"
SelectedItemPath="{Binding SelectedItemPath}"
RemoveCommand="{Binding ExplorerControlItemRemovedCommand}"/>
Proposed Solution:
In your MenuItem Commands try using Ancestral Binding.
<MenuItem x:Name="myTemplate" Header="Remove"
Command="{Binding RelativeSource={RelativeSource Path=RemoveCommand, AncestorType={x:Type ExplorerControl}, Mode=FindAncestor" />
I believe the reason your DataContext is changing is because you're pointing to Nodes and showing each Node in the MenuItem. However, Node does not contain the command you are trying to bind to.
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
If you are unsure of your DataContext you can use Snoop to see what is the current DataContext.
Extra Info:
I don't think you need to point DataContext of your TreeView. It's passed down automatically.
<TreeView.DataContext>
<local:ExplorerControl x:Name="explorer" />
</TreeView.DataContext>
You don't have to use a DependencyProperty with an ICommand. In the constructor of your ExplorerControl you can instantiate the ICommand to a DelegateCommand.
Make a DelegateCommand class that inherits from ICommand. This will be your concrete implementation of ICommand. You can find that here:http://www.wpftutorial.net/delegatecommand.html
Instantiate your ICommands with a DelegateCommand and pass your method, that is on ExplorerControl, to the constructor.
For example:
public class ExplorerControl : UserControl
{
public DelegateCommand RemoveCommand { get; set; }
public ExplorerControl()
{
RemoveCommand = new DelegateCommand(Remove);
}
private void Remove()
{
// Do something here.
}
}
Finally I found a solution.
First of all I found that about ContextMenu:
Because a ContextMenu in WPF does not exist within the visual tree of your page/window/control per se, data binding can be a little tricky.
Source
With the example, I wrote this code and I got that it works well:
<Style TargetType="{x:Type local:ExplorerControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ExplorerControl}">
<Border>
<TreeView Name="myTreeView">
<TreeView.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FF003BB0" />
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal"
Tag="{Binding TemplatedParent,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem x:Name="myTemplate"
Header="Remove"
DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"
Command="{Binding Path=Tag.RemoveCommand}"
CommandParameter="{Binding Path=DataContext}">
</MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I save in the Stackpanel tag, the reference of my explorerControl, then I use PlacementTarget to get the Stackpanel reference
I hope this code helps other people in future.
I have a problem. I am trying to create a context menu with databinding in wpf. The context menu items would are bound to an observable collection of objects. The population of context menu is fine - however, I want to add the command to it.
The way I am using it is:
in XAML
<Grid.Resources>
<local:RestoreCommand x:Key="RestoreCommand" />
<local:ShowBalloonCommand x:Key="BaloonCommand" />
<local:StartTaskCommand x:Key="StartTaskCommand" />
</Grid.Resources>
<ContextMenu ItemsSource="{Binding}" Name="taskBarContextMenu">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{StaticResource StartTaskCommand}"/>
<Setter Property="CommandParameter" Value="{Binding mainWindow}"/>
</Style>
</ContextMenu.ItemContainerStyle>
and
<TextBlock TextWrapping="Wrap" Text="{Binding Name}" Grid.Column="0"/>
<TextBlock TextWrapping="Wrap" Text="{Binding TimeElapsed, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="2"/>
and in C#:
taskbarIcon.ContextMenu.ItemsSource = TasksList;
And I have a class for the command
public class StartTaskCommand : ICommand
{
public void Execute(object parameter)
{
//THE PARAMETER IS ALWAYS NULL
var window = parameter as MainWindow;
if (window != null)
{
}
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
I have it set up simiarly for other two commands and it works fine. Anything I try to add as the parameter is always null - be it taskBarContextMenu, or mainWindow or menuItem...
Any ideas welcome.
====
I tried a following solution as suggested, but the command parameter is still null:
<tb:TaskbarIcon Name="taskbarIcon"
DoubleClickCommand="{StaticResource RestoreCommand}"
DoubleClickCommandParameter="{Binding ElementName=mainWindow}"
LeftClickCommand="{StaticResource BaloonCommand}"
LeftClickCommandParameter="{Binding ElementName=mainWindow}"
IconSource=".\256px-Out_of_date_clock_icon.ico"
MenuActivation="RightClick"
Tag="{Binding ElementName=mainWindow}"
>
<tb:TaskbarIcon.ContextMenu ><ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}" Tag="{Binding}" Name="taskBarContextMenu">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{StaticResource StartTaskCommand}"/>
<Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.DataContext}"/>
</Style>
</ContextMenu.ItemContainerStyle>
You need to add a tag to the menu's container and bind to it using placement target.
View this example:
<StackPanel x:Key="ConfigurationListItem" x:Shared="False" Tag="{Binding ElementName=UserControl}">
<StackPanel Orientation="Horizontal">
<Button>
<Button.InputBindings>
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding ElementName=UserControl, Path=LaunchCommand}" CommandParameter="{Binding}" />
<MouseBinding Gesture="LeftClick" Command="{Binding ElementName=UserControl, Path=SelectCommand}" CommandParameter="{Binding}" />
</Button.InputBindings>
</StackPanel>
<StackPanel.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}" Tag="{Binding}">
<MenuItem Header="Sync Environment Dependencies"
Command="{Binding Parent.PlacementTarget.Tag.SyncEnvironmentCommand, RelativeSource={RelativeSource Self}}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.DataContext}" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
I'm trying to bind the SelectedItem to a View. But the view is not able to access the viewmodel when it is inside the Resources block.
When the datacontext is re-assigned to the children, the binding works for textblocks but not for UserControl (NoteView)
Am I missing any Binding?
PFB revised(entire) code and inline comments.
<UserControl x:Class="Konduva.View.NoteSearchView"
<!-- other namespaces here -->
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding NoteSearch, Source={StaticResource Locator}}">
<Grid>
<ListView ItemsSource="{Binding Notes}"
SelectedItem="{Binding SelectedNote}">
<ListView.Resources>
<DataTemplate DataType="{x:Type vm:NoteViewModel}">
<DockPanel>
<TextBlock Text="{Binding Title}" />
<Popup Placement="Right"
PlacementTarget="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
IsOpen="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}">
<StackPanel>
<!-- This is working --> <TextBlock Text="{Binding SelectedNote.Title}" />
<!-- This is not working --> <v:NoteView DataContext="{Binding SelectedNote}" />
</StackPanel>
</Popup>
</DockPanel>
</DataTemplate>
</ListView.Resources>
</ListView>
</Grid>
</UserControl>
NoteView:
<Grid>
<TextBlock Text="{Binding Title}" /> // This Text is not displayed
</Grid>
Update 3
Since you're using MvvmLight: in NoteView, try changing
DataContext="{Binding Note, Source={StaticResource Locator}}"
to
<UserControl.Style>
<Style TargetType="UserControl">
<Setter Property="DataContext" Value="{Binding Note, Source={StaticResource Locator}}"/>
</Style>
</UserControl.Style>
Update 2
Encountered a similar problem a few minutes ago which I didn't fully understand so I'll throw in the same solution here to see if it helps. What happends if you change it to this?
<v:NoteView DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type Popup}},
Path=DataContext.SelectedNote}"/>
Update
I'm unable to reproduce this. Try adding this in your NoteView constructor. Do you reach DataContextChangedHandler when you change the selection in the ListView?
public NoteView()
{
InitializeComponent();
DependencyPropertyDescriptor dpd =
DependencyPropertyDescriptor.FromProperty(UserControl.DataContextProperty,
typeof(UserControl));
if (dpd != null)
{
dpd.AddValueChanged(this, new EventHandler(DataContextChangedHandler));
}
}
void DataContextChangedHandler(object sender, EventArgs e)
{
MessageBox.Show("DataContext Changed: " + DataContext);
}
First answer
Your DockPanel will get the NoteViewModel as a DataContext and not the ListView and since this DataContext is inherited by all Childs every child will end up with a NoteViewModel as DataContext. To use the ListView as a DataContext for the Popup you can do this. I'm not sure what the DataContext Binding for the StackPanel does though, so I might be missing something here..
<DataTemplate DataType="{x:Type vm:NoteViewModel}">
<DockPanel>
<TextBlock Text="{Binding Title}" />
<Popup Placement="Right"
PlacementTarget="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
IsOpen="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}">
<StackPanel>
<TextBlock Text="{Binding SelectedNote.Title}" />
<StackPanel>
<v:NoteView DataContext="{Binding SelectedNote}"/>
</StackPanel>
</StackPanel>
</Popup>
</DockPanel>
</DataTemplate>
Instead of inserting a NoteView directly and binding the DataContext, use a ContentPresenter:
<ContentPresenter Content="{Binding SelectedNote}>
<ContentPresenter.ContentTemplate>
<DataTemplate>
<v:NoteView />
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>