I am using Caliburn.Micro. I have tried the solutions I found for this problem but is no good. I have the following XAML code for my design:
<Grid x:Name="ActionGrid">
<MenuItem Header="Action" FontFamily="Open Sans" FontSize="14" HorizontalContentAlignment="Right" Foreground="White" x:Name="miAction" Margin="5" Background="#FF166FC4" Tag="{Binding DataContext}">
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="Tag" Value="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=MenuItem}}"/>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}">
<MenuItem Header="Remove Group" cal:Message.Attach="RemoveClicked()" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</MenuItem.Style>
</MenuItem>
</Grid>
<UserControl.DataContext>
<vm:TransactionViewModel/>
</UserControl.DataContext>
Everytime I click on the Item, it returns No Method Found for RemoveClicked. I don't know what I did wrong. Please help me point it out.
Tag="{Binding DataContext}" should be Tag="{Binding}" and the cal:Action.TargetWithoutContext attached property should be set on the MenuItem. Then it works if you right click on the MenuItem to open the ContextMenu:
<MenuItem Header="Action" FontFamily="Open Sans" FontSize="14" HorizontalContentAlignment="Right" Foreground="White" x:Name="miAction"
Margin="5" Background="#FF166FC4" Tag="{Binding}">
<MenuItem.Style>
<Style TargetType="{x:Type MenuItem}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Remove Group"
cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
cal:Message.Attach="RemoveClicked()" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</MenuItem.Style>
</MenuItem>
Use an EventTrigger to open the ContextMenu on left click doesn't work with bindings and this has nothing to do with Caliburn.Micro:
WPF Context menu on left click
You may replace the EventTrigger with an attached behaviour.
I'm not sure, but you can test this:
<MenuItem Header="Remove Group" cal:Message.Attach="RemoveClicked" />
I'm trying to make a File Attachment function in my program, i have 2 types of attachments (Personal/Professional documents). Picture below.
What i want to do now, is make the uploaded files appear in a vertical list (below the label & button in each groupbox) as a label with a delete button, i dont know what this function is called. I would like something like the keywords/tags function (like on stackoverflow, youtube...) Picture below.
Like:
Drivers License [X]
Passport [X]
Visa [X]
As the user can quickly see what files he have alredy uploaded, and quickly remove a file if he made a mistake.
What i have tried so far, is making a stackpanel divided into 2 columns, text on one side, and buttons on the other side, but i didnt get the result that i wanted. Problem is that i dont even know what this function is called, im sure Theres some tutorial somewhere out there, but its hard to search for something you dont know the name of.
Use ListView with the style:
<Style x:Key="ListViewPlate" TargetType="{x:Type ListView}">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth),
RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
ItemWidth="{Binding (ListView.View).ItemWidth,
RelativeSource={RelativeSource AncestorType=ListView}}"
MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
ItemHeight="{Binding (ListView.View).ItemHeight,
RelativeSource={RelativeSource AncestorType=ListView}}" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
And ListView ItemTemplate - in order to works with the delete button use Command (that would require using a Prism), command would transfer selected item as a context.
<DataTemplate x:Key="ListViewPlateItem">
<WrapPanel>
<Border Background="Black" />
<Border BorderBrush="Goldenrod" BorderThickness="2">
<TextBlock HorizontalAlignment="Center" Text="{Binding Name}" VerticalAlignment="Center" />
</Border>
<Border BorderBrush="Goldenrod" BorderThickness="2">
<Button Command="{Binding ElementName = ListViewElement, Path = DataContext.Command"} CommandParameter={"Binding"}">
<Button.Background>
<ImageBrush ImageSource="yourImage.png" TitleMode="None"/>
</Button.Background>
</Button>
</Border>
</WrapPanel>
</DataTemplate>
You can made style and ItemTemplate a ResourceDictionary, and then use it
<ListView ItemTemplate="{StaticResource ListViewPlateItem}" Style="{StaticResource ListViewPlate}"/>
Here is UserControl that is looking like
Xaml code
<UserControl x:Class="ButtonLikeInSO.SpecialTextPresenterWithButton"
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"
d:DesignHeight="300" d:DesignWidth="150" x:Name="This">
<UserControl.Resources>
<SolidColorBrush x:Key="GrayButtonBackGround" Color="Gainsboro"/>
<SolidColorBrush x:Key="RedButtonBackground" Color="Tomato"/>
<Style x:Key="ChangeContentOnMouseOverWithAnimationWhenPressed" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="{StaticResource GrayButtonBackGround}"/>
<Setter Property="Foreground" Value="Black"></Setter>
<Setter Property="ToolTip" Value="Delete Uploading"/>
<Setter Property="ToolTipService.Placement" Value="Top"/>
<Setter Property="Opacity" Value="0.8"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="LayoutRoot" RenderTransformOrigin="0.5 0.5" Margin="2">
<Grid.RenderTransform>
<ScaleTransform></ScaleTransform>
</Grid.RenderTransform>
<Ellipse x:Name="MyBorder" Fill="{TemplateBinding Background}" Stroke="Gray" StrokeThickness="1"/>
<Ellipse x:Name="RectangleVisibleOnMouseMove" Opacity="0" Fill="{StaticResource RedButtonBackground}" Stroke="Black" StrokeThickness="1"/>
<Path x:Name="ButtonPath"
Margin="5"
Stroke="{TemplateBinding Foreground}"
StrokeThickness="1.5"
StrokeStartLineCap="Square"
StrokeEndLineCap="Square"
Stretch="Uniform"
VerticalAlignment="Center"
HorizontalAlignment="Center" Data="M0,0 L1,1 M0,1 L1,0">
</Path>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RectangleVisibleOnMouseMove"
Storyboard.TargetProperty="(FrameworkElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyBorder"
Storyboard.TargetProperty="(FrameworkElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="RectangleVisibleOnMouseMove"
Storyboard.TargetProperty="(FrameworkElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MyBorder"
Storyboard.TargetProperty="(FrameworkElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewMouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<EasingDoubleKeyFrame KeyTime="0:0:0.10" Value="0.8" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
<EasingDoubleKeyFrame KeyTime="0:0:0.10" Value="0.8" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewMouseUp">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.8" />
<EasingDoubleKeyFrame KeyTime="0:0:0.10" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot"
Storyboard.TargetProperty="(Grid.RenderTransform).(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.8" />
<EasingDoubleKeyFrame KeyTime="0:0:0.10" Value="1.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Button.IsPressed" Value="True">
<Setter Property="Foreground" Value="White"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="False">
<Setter Property="Foreground" Value="Black"></Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="1.0"></Setter>
</Trigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="TextWithDeleteButton">
<Border BorderThickness="1" BorderBrush="Gainsboro">
<Grid Background="{Binding ElementName=This, Path=Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding ElementName=This, Path=Text}" MaxWidth="150" Margin="5,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center"
TextTrimming="WordEllipsis" />
<Button Grid.Column="1" Margin="0" Width="20" Height="20" HorizontalAlignment="Center" VerticalAlignment="Center" Command="{Binding ElementName=This, Path=DeleteCommand}" Style="{StaticResource ChangeContentOnMouseOverWithAnimationWhenPressed}"></Button>
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentControl ContentTemplate="{StaticResource TextWithDeleteButton}"></ContentControl>
</Grid>
Code behind
public partial class SpecialTextPresenterWithButton : UserControl
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof (string),
typeof (SpecialTextPresenterWithButton), new PropertyMetadata(default(string)));
public static readonly DependencyProperty DeleteCommandProperty = DependencyProperty.Register("DeleteCommand",
typeof (ICommand), typeof (SpecialTextPresenterWithButton), new PropertyMetadata(default(ICommand)));
public SpecialTextPresenterWithButton()
{
InitializeComponent();
}
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public ICommand DeleteCommand
{
get { return (ICommand) GetValue(DeleteCommandProperty); }
set { SetValue(DeleteCommandProperty, value); }
}
}
Using
<!--you can use binding to DeleteCommand and Text they are dependancy properties-->
<buttonLikeInSo:SpecialTextPresenterWithButton Background="Aquamarine" DeleteCommand="{Binding DeleteCommand}" HorizontalAlignment="Center" VerticalAlignment="Center" Height="20" Text="LoooooooooooongFileName"/>
Assuming you have some type of View Model with data-binding, this can be quite straight forward. You can have an ObservableCollection of uploaded items. This could just be a simple class holding an identifyer and display name:
public class UploadedFileInfo
{
public int Id { get; set; }
public string DisplayName { get; set; }
}
in View Model:
ObservableCollection<UploadedFileInfo> UploadedFiles { get; set; }
Now you can bind a ItemsControl to this collection eg:
<ItemsControl ItemsSource="{Binding UploadedFiles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding DisplayName, Mode=OneWay}" />
<Button Command="{Binding Path=DataContext.DeleteFile, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding Id}" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This requires a command in the View Model:
public ICommand DeleteFile { get; private set;}
In View Model Constructor:
DeleteFile = new RelayCommand<int>((fileIdToDelete) => deleteFile(fileIdToDelete))
Where deleteFile(int fileToDelete) is a function to delete the file and remove it from the ObservableCollection UploadedFiles
Note, you will have to find the RelayCommand class, there is one on the Microsoft WPF pages, there are also implementations in MVVMLight and other MVVM frameworks that you can use.
EDIT
A binding in an ItemsControl will look for properties on the objects bound to (that is its DataContext)
<Button Command="{Binding DeleteFile}" CommandParameter="{Binding Id}" />
Should have been
<Button Command="{Binding Path=DataContext.DeleteFile, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding Id}" />
Which will look for the ICommand parameter on the main window's DataContext
I am trying to make rectangle animation after clicking on a button.
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
<Button Content="FirstButton" HorizontalAlignment="Left" Height="60" Margin="341,91,0,0" VerticalAlignment="Top" Width="91">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
??? <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
What i need to write?
<StackPanel>
<Button Name="Button"/>
<Rectangle>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Button, Path=IsPressed}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</StackPanel>
I have gone through some of the previous similar questions, but am still having issues with the ContextMenuService.Placement. Please suggest.
It worked fine when I followed this approach
<Button x:Name="btn" Content="button" Click="b_Click" >
<Button.ContextMenu >
<ContextMenu >
<MenuItem Header="Open" Command="{Binding OnOpen}" ></MenuItem>
<MenuItem Header="Close" Command="{Binding OnClose}"></MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
private void be_Click(object sender, RoutedEventArgs e)
{
btn.ContextMenu.PlacementTarget = btn;//Like this
btn.ContextMenu.Placement = PlacementMode.Top;//Like this
btn.ContextMenu.DataContext = btn.DataContext;
btn.ContextMenu.IsOpen = true;
}
But it doesn't work with MVVM pattern.
<Button x:Name="btn" VerticalAlignment="Bottom" ContextMenuService.IsEnabled="False">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsEnabled">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu Name="AddReportContextMenu" HorizontalAlignment="Right">
<MenuItem Header="Open" Command="{Binding OnOpen}" ></MenuItem>
<MenuItem Header="Close" Command="{Binding OnClose}"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
I tried adding it in setter like this
<Setter Property="ContextMenu.PlacementTarget" Value="{Binding ElementName=btn}"></Setter>
<Setter Property="ContextMenu.Placement" Value="Top"></Setter>
Or Like this:
<Setter Property="ContextMenuService.Placement" Value="Top"></Setter>
The placement property worked well with right click like this if ContextMenuService.IsEnabled is not set it false. I had to set it false to make sure that the ContextMenu only worked with Left Click.
<Button x:Name="btn" ContextMenuService.Placement="Top">
Thank you!
I have been for 2 days now trying to develop my own WPF textbox for no avail.
My initial try was inheriting from a control and then adding a template with all the stuff I wanted (a border and an asterisk in the outside).
Generic.xaml file:
<Style TargetType="{x:Type local:BdlTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:BdlTextBox">
<Grid x:Name="ContentGrid">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="Tbl" Text="*" Foreground="Red" FontSize="15" Margin="0,-4,0,0"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:BdlTextBox}},
Path=IsRequired, Converter={StaticResource myBoolToVisibilityConverter}}"/>
<Rectangle Grid.Column="1" x:Name="Bg" Fill="Red" Opacity="0"/>
<TextBox Grid.Column="1" x:Name="Tb" Margin="1,1,1,1"/>
</Grid>
</Grid>
<ControlTemplate.Resources>
<Storyboard x:Key="flashAnimation">
<DoubleAnimation Storyboard.TargetName="Bg" Storyboard.TargetProperty="Opacity" From="0" To="1" AutoReverse="True" Duration="0:0:0.5" RepeatBehavior="2x" />
<DoubleAnimation Storyboard.TargetName="Bg" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5" BeginTime="0:0:2"/>
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=HasValidationError}" Value="True" >
<DataTrigger.EnterActions>
<BeginStoryboard Name="flash" Storyboard="{StaticResource flashAnimation}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="flash"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=HasValidationError}" Value="False" >
<Setter TargetName="Bg" Property="Opacity" Value="0"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem is: I cannot use the control as a Textbox (the reason is obvious). I can't even properly use the Text property. So I was wondering what could be done to solve this problem.
Dependency Properties are also a problem. I have tried to "clone" the Text property from the Textbox "Tb", but failed too.