I am trying to do a tool for rectangle drawing and moving by ListBox in WPF. I use MouseLeftButtonDownOnRectangle to select rectangle, MouseMoveOnRectangle to drag rectangle, and MouseLeftButtonUpOnRectangle to drop rectangle. MouseLeftButtonDownOnRectangle and MouseMoveOnRectangle work ok, but MouseLeftButtonUpOnRectangle does not fire after MouseMoveOnRectangle. I have tried preview-event and non-preview-event, both of them do not work.
XAML
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
<Style TargetType="ListBox" x:Key="ShapesListBoxStyle">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/>
</Style>
<Style TargetType="ListBoxItem" x:Key="ShapesItemStyle">
<Setter Property="Canvas.Left" Value="{Binding Rectangle.X}"/>
<Setter Property="Canvas.Top" Value="{Binding Rectangle.Y}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Rectangle
x:Name="LabelShapeFill"
HorizontalAlignment="Left"
Width="{Binding Rectangle.Width}"
Height="{Binding Rectangle.Height}"
Fill="{Binding Hexadecimal}"
Stroke="{Binding Hexadecimal}"
Opacity="0.1">
</Rectangle>
<Rectangle
x:Name="LabelShapeBorder"
HorizontalAlignment="Left"
Width="{Binding Rectangle.Width}"
Height="{Binding Rectangle.Height}"
Stroke="{Binding Hexadecimal}"
StrokeThickness="1">
</Rectangle>
<Grid Height="20" Margin="0 0 0 -20" VerticalAlignment="Bottom" Visibility="Collapsed" x:Name="LabelShapeControlPanel">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="45"/>
</Grid.ColumnDefinitions>
<Button Content="Delete" Width="45" Height="20" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Viewbox>
<Grid>
<b:Interaction.Triggers>
<b:EventTrigger EventName="PreviewMouseLeftButtonDown">
<b:InvokeCommandAction Command="{Binding PreviewMouseLeftButtonDownOnWindow}"/>
</b:EventTrigger>
<b:EventTrigger EventName="MouseLeftButtonDown">
<b:InvokeCommandAction Command="{Binding MouseLeftButtonDownOnWindow}"/>
</b:EventTrigger>
<b:EventTrigger EventName="PreviewMouseLeftButtonUp">
<b:InvokeCommandAction Command="{Binding PreviewMouseLeftButtonUpOnWindow}"/>
</b:EventTrigger>
<b:EventTrigger EventName="MouseLeftButtonUp">
<b:InvokeCommandAction Command="{Binding MouseLeftButtonUpOnWindow}"/>
</b:EventTrigger>
<b:EventTrigger EventName="MouseMove">
<b:InvokeCommandAction Command="{Binding MouseMoveOnWindow}"/>
</b:EventTrigger>
</b:Interaction.Triggers>
<b:Interaction.Behaviors>
<mb:MouseBehaviour MouseX="{Binding MouseX, Mode=OneWayToSource}" MouseY="{Binding MouseY, Mode=OneWayToSource}" />
</b:Interaction.Behaviors>
<Image x:Name="Img" Source="{Binding CurrentPhoto}" RenderOptions.BitmapScalingMode="Unspecified" Stretch="Uniform"/>
<ListBox
ItemsSource="{Binding Shapes}"
Width="{Binding ActualWidth, ElementName=Img}"
Height="{Binding ActualHeight, ElementName=Img}"
VerticalAlignment="Top"
HorizontalAlignment="Left"
SelectionMode="Extended"
Style="{StaticResource ShapesListBoxStyle}"
ItemContainerStyle="{StaticResource ShapesItemStyle}"
SelectedIndex="{Binding SelectedShapeIndex}">
<b:Interaction.Triggers>
<b:EventTrigger EventName="PreviewMouseLeftButtonDown">
<b:InvokeCommandAction Command="{Binding PreviewMouseLeftButtonDownOnRectangle}"/>
</b:EventTrigger>
<b:EventTrigger EventName="MouseLeftButtonDown">
<b:InvokeCommandAction Command="{Binding MouseLeftButtonDownOnRectangle}"/>
</b:EventTrigger>
<b:EventTrigger EventName="PreviewMouseLeftButtonUp">
<b:InvokeCommandAction Command="{Binding PreviewMouseLeftButtonUpOnRectangle}"/>
</b:EventTrigger>
<b:EventTrigger EventName="MouseLeftButtonUp">
<b:InvokeCommandAction Command="{Binding MouseLeftButtonUpOnRectangle}"/>
</b:EventTrigger>
<b:EventTrigger EventName="PreviewMouseMove">
<b:InvokeCommandAction Command="{Binding PreviewMouseMoveOnRectangle}"/>
</b:EventTrigger>
<b:EventTrigger EventName="MouseMove">
<b:InvokeCommandAction Command="{Binding MouseMoveOnRectangle}"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</ListBox>
<Canvas
Width="{Binding ActualWidth, ElementName=Img}"
Height="{Binding ActualHeight, ElementName=Img}">
<Border
Canvas.Left="{Binding DrawStartX}"
Canvas.Top="{Binding DrawStartY}"
x:Name="dragSelectionBorder"
Width="{Binding DrawWidth}"
Height="{Binding DrawHeight}"
BorderBrush="{Binding Hexadecimal}"
BorderThickness="2"
Background="LightBlue"
Opacity="0.5"/>
</Canvas>
</Grid>
</Viewbox>
I use the following code to get mouse position. I suspect this code cause the problem. But I have no idea how to fix it.
MouseBehaviour.cs
using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Core
{
public class MouseBehaviour : Behavior<Grid>
{
public static readonly DependencyProperty MouseYProperty = DependencyProperty.Register(
"MouseY", typeof(double), typeof(MouseBehaviour), new PropertyMetadata(default(double)));
public static readonly DependencyProperty MouseXProperty = DependencyProperty.Register(
"MouseX", typeof(double), typeof(MouseBehaviour), new PropertyMetadata(default(double)));
public double MouseY
{
get { return (double)GetValue(MouseYProperty); }
set { SetValue(MouseYProperty, value); }
}
public double MouseX
{
get { return (double)GetValue(MouseXProperty); }
set { SetValue(MouseXProperty, value); }
}
protected override void OnAttached()
{
AssociatedObject.MouseMove += AssociatedObjectOnMouseMove;
}
private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
{
var pos = mouseEventArgs.GetPosition(AssociatedObject);
MouseX = pos.X;
MouseY = pos.Y;
}
protected override void OnDetaching()
{
AssociatedObject.MouseMove -= AssociatedObjectOnMouseMove;
}
}
}
Screenshot
Related
Hi i have the same problem as here Button within ListBox ItemTemplate not selecting item
And i know the reason why my button doesnt see selected item, it because listbox is called when MouseDown
and button is called on Click. But i dont know how to fix it
XAML
<ListBox Grid.Row="1" x:Name="ListViewProduct" Background="#FFf1f1f1" ItemsSource="{Binding Videos}" >
<ListBox.ItemTemplate>
<!-- FIX Ripple-->
<DataTemplate >
<Border Background="White" Name="border" Margin="50 10 50 10" Width="310" Height="360">
<StackPanel>
<Border Width="300" Height="300" CornerRadius="5" Margin="5">
<Border.Effect>
<DropShadowEffect ShadowDepth="5"/>
</Border.Effect>
<Border.Background>
<ImageBrush ImageSource="{Binding Image}"/>
</Border.Background>
</Border>
<Grid>
<StackPanel>
<TextBlock Margin="5" Text="{Binding Name}" FontSize="14" FontFamily="Franklin Gothic Medium" />
<TextBlock Margin="5 0" Text="{Binding User.Name}" FontSize="13" />
</StackPanel>
<Button HorizontalAlignment="Right" Margin="0 0 10 0"
Command="{Binding ElementName= ListViewProduct,Path=DataContext.DownloadPageCommand}"
CommandParameter="{Binding Path=SelectedItem , ElementName=ListViewProduct}">
<materialDesign:PackIcon Width="25" Height="25" Kind="Download" Foreground="White"/>
</Button>
</Grid>
</StackPanel>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding ElementName= ListViewProduct,Path=DataContext.ViewWatchingPageCommand}"
CommandParameter="{Binding Path=SelectedItem , ElementName=ListViewProduct}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
C#
private RelayCommandParametr _downloadpageCommand;
public RelayCommandParametr DownloadPageCommand
{
get
{
return _downloadpageCommand
?? (_downloadpageCommand = new RelayCommandParametr(
obj =>
{
SelectedVideo = obj as Video;
_navigationService.NavigateTo("Download",obj);
}));
}
}
private RelayCommandParametr _viewWatchingPageCommand;
public RelayCommandParametr ViewWatchingPageCommand
{
get
{
return _viewWatchingPageCommand
?? (_viewWatchingPageCommand = new RelayCommandParametr(
(obj) =>
{
SelectedVideo = obj as Video;
_navigationService.NavigateTo("VideoWatching",SelectedVideo);
}));
}
}
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
I find answer i just set selected item.
I have got a problem with my WPF MVVM application.
I have got a view (CaisseView.xaml) and its ViewModel (CaisseViewModel.cs which is used as Datacontext of the View called since another .cs).
Into my view i am using an itemsControl in order to have a button for each element of a observablecollection of a Model. Moreover into my view I have got an ListView. I want that every time a button of the itemsControl is clicked a new line appears into my Lisview.
This last thing is what it does not work!!
Using debug I enter into my command, the command add an object into my observable collection but the app does not actualize the View.
Into my ViewModel, I am using INotifyPropertyChanged, RelayCommand and ICommand.
I let you my code.
Can you help me with my matter ???
thanks:
My View :
<UserControl x:Class="LMarket.Views.CaisseView"
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"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:LMarket.Views"
xmlns:localM="clr-namespace:LMarket.Models"
xmlns:localModel="clr-namespace:LMarket.ViewModels"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d">
<UserControl.Resources>
<localModel:CaisseViewModel x:Key="CaisseViewModel"/>
<localM:ProduitDuStock x:Key="ProduitDuStockModel"/>
</UserControl.Resources>
<Grid Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Cursor="Hand" Source="/Resources/homepage.png" Width="32" Height="32" HorizontalAlignment="Left" Margin="15,10" Grid.Row="0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding DataContext.OnHomeCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<Image Cursor="Hand" Source="/Resources/LogOut.png" Width="32" Height="32" HorizontalAlignment="Right" Margin="15,10" Grid.Row="0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding DataContext.BackConnectionCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderThickness="2" BorderBrush="Azure" Margin="5,5,1,5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="1*" />
<RowDefinition Height="50" />
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="#FFC2E0ED">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Image Cursor="Hand" VerticalAlignment="Center" Width="32" Height="32" Source="/Resources/files-and-folders.png"/>
<Image Cursor="Hand" VerticalAlignment="Center" Margin="10,0" Width="32" Height="32" Source="/Resources/cancel.png"/>
</StackPanel>
</Grid>
<ListView Grid.Row="1" Margin="5" SelectionMode="Single"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Path=LstProducts, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListView.ItemTemplate>
<DataTemplate DataType="localM:ProduitDuStock">
<StackPanel Margin="2" MinWidth="244">
<StackPanel.Resources>
<Style TargetType="{x:Type StackPanel}">
<!-- <Style.Triggers>
<DataTrigger Binding="{Binding Path=Selected}" Value="True">
<Setter Property="Background" Value="LightBlue"/>
</DataTrigger>
</Style.Triggers> -->
</Style>
</StackPanel.Resources>
<DockPanel >
<TextBlock FontWeight="Bold" Text="Produit: " DockPanel.Dock="Left" Margin="5,0,5,0"/>
<TextBlock Text=" " />
<TextBlock Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="Green" FontWeight="Bold" />
</DockPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<DockPanel Grid.Row="2" Margin="5" Background="#FF296B88">
<Label Content="TOTAL" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" FontFamily="Rockwell Condensed" Foreground="#FFF2FF5A" />
<Label Content="$$" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="14" FontWeight="Bold" FontFamily="Rockwell Condensed" Foreground="#FFF2FF5A" />
</DockPanel>
<Grid Grid.Row="3" Background="#FFC2E0ED">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="2">
<Button Cursor="Hand" Width="80" Content="Cuenta %" Background="#FF98ADA8" BorderBrush="#FF4A6DFF" Margin="2,0">
<Button.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="8"/>
</Style>
</Button.Resources>
</Button>
<Button Cursor="Hand" Width="80" Content="Producto %" Background="#FF98ADA8" BorderBrush="#FF4A6DFF" Margin="2,0">
<Button.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="8"/>
</Style>
</Button.Resources>
</Button>
<Button Cursor="Hand" Width="80" Content="-1" Background="#FFDDCF00" BorderBrush="#FF4A6DFF" FontWeight="Bold" FontSize="20">
<Button.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="8"/>
</Style>
</Button.Resources>
</Button>
<Button Cursor="Hand" Width="80" Content="+1" Background="#FF79C837" BorderBrush="#FF4A6DFF" FontWeight="Bold" FontSize="20" Margin="2,0">
<Button.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="8"/>
</Style>
</Button.Resources>
</Button>
<Button Cursor="Hand" Width="auto" Content=" Validar para Pagar " Command="{Binding AddNewProductCommand}" Background="#FF98ADA8" BorderBrush="#FF4A6DFF" FontSize="19" Margin="80,0,2,0" Foreground="Black">
<Button.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="8"/>
</Style>
</Button.Resources>
</Button>
</StackPanel>
</Grid>
</Grid>
</Border>
<Border Grid.Column="1" BorderThickness="2" BorderBrush="Azure" Margin="1,5,5,5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" MaxHeight="720"/>
<RowDefinition Height="1" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" Background="Transparent"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding ListOfProducts}" MaxWidth="762">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Cursor="Hand" CornerRadius="8" Margin="4,3" BorderThickness="1.5" BorderBrush="#FFFDFF00">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF6F92DC" Offset="1"/>
<GradientStop Color="#FFA6DBFF" Offset="0.534"/>
</LinearGradientBrush>
</Border.Background>
<Button BorderBrush="Transparent" Background="Transparent" Command="{Binding Source={StaticResource CaisseViewModel}, Path=AddNewProductCommand}" CommandParameter="{Binding Id}">
<Button.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="8"/>
</Style>
</Button.Resources>
<StackPanel Orientation="Vertical" Margin="2" Width="80" Height="80">
<Image Source="{Binding ProductImageUrl}" Width="40" Height="40" Margin="0,10,0,5"
HorizontalAlignment="Center"/>
<Label Content="{Binding Surname}" FontWeight="Bold" HorizontalAlignment="Center" FontSize="11"/>
</StackPanel>
</Button>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Border>
</Grid>
</Grid>
</UserControl>
And my ViewModel:
using LMarket.Models;
using LMarket.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xml;
namespace LMarket.ViewModels
{
class CaisseViewModel : INotifyPropertyChanged
{
//Event for INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] string str = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(str));
}
#region Attributs
private ObservableCollection<ProduitDuStock> listOfProducts;
private ObservableCollection<ProduitDuStock> lstProducts;
private ProduitDuStock selectedProduct;
#endregion
#region Getter/Setter
public ObservableCollection<ProduitDuStock> ListOfProducts
{
get
{
return listOfProducts;
}
set
{
if (listOfProducts != value)
{
listOfProducts = value;
}
NotifyPropertyChanged();
}
}
public ObservableCollection<ProduitDuStock> LstProducts
{
get
{
return lstProducts;
}
set
{
if (lstProducts != value)
{
lstProducts = value;
}
NotifyPropertyChanged();
}
}
public ProduitDuStock SelectedProduct
{
get
{
return selectedProduct;
}
set
{
if (selectedProduct != value)
{
selectedProduct = value;
NotifyPropertyChanged();
}
}
}
#endregion
#region Constructeur
public CaisseViewModel()
{
ListOfProducts = new ObservableCollection<ProduitDuStock>();
LstProducts = new ObservableCollection<ProduitDuStock>();
toto();
//Lecture du fichier ou son enregistrer les données du stock (En local sur un .xml)
try
{
//Ouverture du document XML
XmlDocument xmlDoc = new XmlDocument();
string Path = Directory.GetCurrentDirectory().ToString();
Path = Path + "\\Configuration\\Stockes.xml";
xmlDoc.Load(Path);
//Recupérer la section des produits
XmlNodeList nodeList = xmlDoc.DocumentElement.SelectNodes("/Stockes/Products/product");
//Pour chaque produit dans le fichier, créer un objet ProduitDuStock et l'ajouter à l'ObservableCollection.
foreach (XmlNode node in nodeList)
{
//Creation du nouvel objet
ProduitDuStock testProduit = new ProduitDuStock();
foreach (XmlAttribute att in node.Attributes)
{
//Récupération des parametres de l'objet.
switch (att.Name)
{
case "id":
testProduit.Id = int.Parse(att.Value);
break;
case "name":
testProduit.Name = att.Value;
break;
case "pays":
testProduit.Pays = att.Value;
break;
case "surname":
testProduit.Surname = att.Value;
break;
case "quantite":
testProduit.Quantite = int.Parse(att.Value);
break;
case "unitprice":
testProduit.UnitPrice = int.Parse(att.Value);
break;
case "productImageUrl":
testProduit.ProductImageUrl = att.Value;
break;
default:
break;
}
}
//Ajouter l'objet créé a notre ObservableCollection.
ListOfProducts.Add(testProduit);
}
}
catch (Exception ex)
{
}
}
#endregion
#region Command Definition
//Event RelayCommand Definition
private RelayCommand addProductToBill = null;
public ICommand AddProductToBill
{
get
{
if (addProductToBill == null)
{
addProductToBill = new RelayCommand(OnAddProductToBill);
}
return addProductToBill;
}
}
private RelayCommand addNewProductCommand = null;
public ICommand AddNewProductCommand
{
get
{
if (addNewProductCommand == null)
{
addNewProductCommand = new RelayCommand(OnAddNewProductCommand);
}
return addNewProductCommand;
}
}
#endregion
#region Command function definition
//Event lorsque le curseur rentre dans la zone du boutton "Stock"
private void OnAddNewProductCommand(object obj)
{
toto();
}
private void OnAddProductToBill(object obj)
{
toto();
}
#endregion
#region function
public void toto()
{
ProduitDuStock myAddProductToBill = new ProduitDuStock();
myAddProductToBill.Name = "trrt";
LstProducts.Add(myAddProductToBill);
}
#endregion
}
}
the important part into the view is the next:
<Button BorderBrush="Transparent" Background="Transparent" Command="{Binding Source={StaticResource CaisseViewModel}, Path=AddNewProductCommand}" CommandParameter="{Binding Id}">
remember that this button is defined into a itemsControl ! So the Datacontextof the button is not my viewModel that why I am using a staticResource...
I hope something will help me :) thank you very much.
Welcome to SO! For future reference, you'll have a much better chance of getting your questions answered if you post an MCVE, there's enough unnecessary code in what you posted to put most people here off.
To answer your question, there are actually many things wrong with this code, but the main issue is that you're creating callback handlers of type RelayCommand, yet your command handler (AddProductToBill) expects an object parameter and should thus be of type RelayCommand<object>. (More confusingly, one of your bindings is passing in CommandParameter, while the other is not).
Another thing to avoid is declaring your view model in your resources block, this is generally not done for a variety of reasons (are you sure you're assigning that instance as your DataContext and not declaring a new one?). If you're assigning your DataContext elsewhere then your list elements can bind to it with something like this:
<UserControl ...
x:Name="_this">
.
.
<!-- Inside ItemsControl.ItemTemplate -->
<Button
Command="{Binding ElementName=_this, Path=DataContext.MyHandler}"
CommandParameter="{Binding}" ... />
<Grid>
<Grid x:Name="thumbGrid" ShowGridLines="True" ClipToBounds="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=ThumbSelectorLeftMargin, Mode=TwoWay}"/>
<ColumnDefinition Width="{Binding Path=ThumbWidthSelector, Mode=TwoWay}"/>
<ColumnDefinition Width="{Binding Path=ThumbSelectorRightMargin, Mode=TwoWay}" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="{Binding Path=ThumbSelectorTopMargin, Mode=TwoWay}" />
<RowDefinition Height="{Binding Path=ThumbHeightSelector, Mode=TwoWay}"/>
<RowDefinition Height="{Binding Path=ThumbSelectorBottomMargin, Mode=TwoWay}"/>
</Grid.RowDefinitions>
<GridSplitter Grid.Column="0" Grid.RowSpan="3" HorizontalAlignment="Right" BorderBrush="Transparent"
BorderThickness="2" ShowsPreview="True" DragCompleted="ThumbLeftGridSplitterDragCompleted" />
<GridSplitter Grid.Column="2" Grid.RowSpan="3" HorizontalAlignment="Left" BorderBrush="Transparent"
BorderThickness="2" ShowsPreview="True" DragCompleted="ThumbRightGridSplitterDragCompleted" />
<Grid x:Name="thumbImgGrid" MouseDown="thumbImgGrid_MouseDown" MouseMove="thumbImgGrid_MouseMove" MouseUp="thumbImgGrid_MouseUp" Grid.Row="1" Grid.Column="1">
<Border x:Name="thumbBorder">
<Image Stretch="Fill"/>
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ThumbBackgroundEntity.FillType}" Value="Color">
<Setter Property="Background" Value="{Binding Path=ThumbBackgroundEntity.BackgroundColor , Mode=TwoWay}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ThumbBackgroundEntity.FillType}" Value="NoFill">
<Setter Property="Background" Value="{Binding Path=ThumbBackgroundEntity.BackgroundColor , Mode=TwoWay}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
<Border Opacity="{Binding Path=ThumbBackgroundEntity.Opacity , Mode=TwoWay}">
<Image x:Name="thumbImage" Source="{Binding Path=ThumbBackgroundEntity.BackgroundImageFullPath , Mode=TwoWay, Converter={StaticResource StringToImgConverter}}"
RenderTransformOrigin="0.5, 0.5" Stretch="Fill">
<Image.LayoutTransform>
<RotateTransform Angle="{Binding Path=ThumbBackgroundEntity.ImageAngle , Mode=TwoWay}"/>
</Image.LayoutTransform>
</Image>
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ThumbBackgroundEntity.FillType}" Value="Color">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ThumbBackgroundEntity.FillType}" Value="NoFill">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</Grid>
<GridSplitter Grid.Row="0" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" BorderBrush="Transparent" BorderThickness="2" ShowsPreview="True"/>
<GridSplitter Grid.Row="2" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Top" BorderBrush="Transparent" BorderThickness="2" ShowsPreview="True" />
</Grid>
</Grid>
I want to move thumbImgGrid inside grid keeping height and width constant(maintain image aspect ratio)
I did following way but i could not maintain the height and width same on move.
On mouse down i calculated top left value of thumbImgGrid
private void thumbImgGrid_MouseDown(object sender, MouseButtonEventArgs e)
{
startTopLeft = thumbImgGrid.TranslatePoint(new Point(0, 0), trackGrid);
startRightBottom = new Point(startTopLeft.X + thumbImgGrid.ActualWidth, startTopLeft.Y + thumbImgGrid.ActualHeight);
thumbImgGrid.CaptureMouse();
}
Mouse move function,here i get the current thumbGrid position and get the difference of points with old and new position and difference is added or subtracted in old value.
private void thumbImgGrid_MouseMove(object sender, MouseEventArgs e)
{
if (thumbImgGrid.IsMouseCaptured)
{
Vector offset = Point.Subtract(e.GetPosition(thumbGrid), startTopLeft);
double newLeft = startTopLeft.X + offset.X;
double NewTop = startTopLeft.Y + offset.Y;
Point newRightBottom = new Point(newLeft + thumbImgGrid.ActualWidth, newLeft+ thumbImgGrid.ActualHeight);
//thumbImgGrid.Margin = new Thickness(newLeft, NewTop, newRightBottom.X, newRightBottom.Y);
_DataSource.ThumbSelectorLeftMargin = new GridLength(newLeft, GridUnitType.Star);
//_DataSource.ThumbWidthSelector = new GridLength(thumbImgGrid.ActualWidth, GridUnitType.Star);
//_DataSource.ThumbSelectorRightMargin = new GridLength(newLeft + thumbImgGrid.ActualWidth, GridUnitType.Star);
_DataSource.ThumbSelectorTopMargin = new GridLength(NewTop, GridUnitType.Star);
//_DataSource.ThumbHeightSelector = new GridLength(thumbImgGrid.ActualHeight, GridUnitType.Star);
// _DataSource.ThumbSelectorBottomMargin = new GridLength(newLeft + thumbImgGrid.ActualHeight, GridUnitType.Star);
_DataSource.UpdateThumbDimnsionLayout();
}
}
Mouse Up Function
private void thumbImgGrid_MouseUp(object sender, MouseButtonEventArgs e)
{
thumbImgGrid.ReleaseMouseCapture();
}
I am unable to maintain the height width constant on mouse move.
Thanks in advance.
I like to Binding the datagrid parent from Behavior (pnlDgSubFooter) placed in DataGrid/GroupStyle/ContainerStyle/Style[GroupItem]/Setter[template]/ControlTemplate/Expander/Header/DockPanel/StackPanel
But the Binding can't leave of DockPanel.
in ElementName, there is only "btnExpandAll" and himself.
In Behavior, the LeDataGrid property return alway null (except if i bind on . or btnExpandAll)
<DataGrid Grid.Row="0" x:Name="dgMain" AutoGenerateColumns="False" SelectionUnit="FullRow" LoadingRow="dgMain_LoadingRow" MouseDown="dgMain_MouseDown" Sorting="dgMain_Sorting"
CanUserReorderColumns="False" CanUserResizeColumns="True" CanUserResizeRows="False" CanUserSortColumns="True" CanUserAddRows="False"
Style="{StaticResource dg}" RowStyle="{StaticResource dgRow}" CellStyle="{StaticResource dgCell}" ColumnHeaderStyle="{StaticResource dgColHeader}" RowHeaderStyle="{StaticResource dgRowHeader}"
ItemsSource="{Binding NotifyOnSourceUpdated=True, Source={StaticResource cvsElmts}}" HorizontalAlignment="Left" >
<!--DataGrid.DataContext><Binding Source="{StaticResource tblUsers}"/></DataGrid.DataContext-->
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<mvvm:EventToCommand Command="{Binding SendCommand, Mode=OneWay}" CommandParameter="{Binding SelectedItem, ElementName=dgMain}" PassEventArgsToCommand="False"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.GroupStyle>
<GroupStyle>
<!-- Style for groups under the top level. -->
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Margin" Value="0,0,0,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="{Binding DataContext.ExpandedAll, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" BorderThickness="1,1,1,5">
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsBottomLevel}" Value="True">
<Setter Property="Margin" Value="8,0,0,0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<Expander.Header>
<DockPanel>
<Button Name="btnExpandAll" Command="{Binding DataContext.ExpandedAllCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" Click="btnExpandAll_Click" ToolTip="{x:Static resx:resMain.lblExpandAll}" BorderThickness="0">
<TextBlock Grid.Column="0" Text="" FontFamily="{StaticResource FntSymbol}" Foreground="{StaticResource scbBlack}" FontSize="12" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Button>
<TextBlock FontWeight="Bold" Text="" Margin="5,0,0,0"><Run Text="{Binding Path=Name, Mode=OneWay}" /><Run Text=" ("/><Run Text="{Binding Path=ItemCount, Mode=OneWay}" /><Run Text=" éléments)."/></TextBlock>
<StackPanel Name="pnlDgSubFooter" HorizontalAlignment="Left" Orientation="Horizontal" >
<i:Interaction.Behaviors>
<Classes:BehaviorWithCommand LeDataGrid="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" LeGroupe="{Binding .}" />
</i:Interaction.Behaviors>
</StackPanel>
</DockPanel>
</Expander.Header>
<Expander.Content>
<Border BorderThickness="1" BorderBrush="{StaticResource scbGrey3}">
<ItemsPresenter />
</Border>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
....
The Behavior:
public class BehaviorWithCommand : Behavior<FrameworkElement> { // StackPanel
public static readonly DependencyProperty LeDataGridProperty = DependencyProperty.Register(nameof(LeDataGrid), typeof(object), typeof(BehaviorWithCommand), new PropertyMetadata(null));
public static readonly DependencyProperty LeGroupeProperty = DependencyProperty.Register(nameof(LeGroupe), typeof(object), typeof(BehaviorWithCommand), new PropertyMetadata(null));
public object LeDataGrid {
get { return (object)GetValue(LeDataGridProperty); }
set { SetValue(LeDataGridProperty, value); }
}
public object LeGroupe {
get { return (object)GetValue(LeGroupeProperty); }
set { SetValue(LeGroupeProperty, value); }
}
protected override void OnAttached() {
base.OnAttached();
((Panel)AssociatedObject).Children.Clear();
var dg = new DataGrid();
dg.Columns.Add(new DataGridTextColumn());
dg.Columns.Add(new DataGridTextColumn());
dg.Columns.Add(new DataGridTextColumn());
//var dg = (DataGrid)LeDataGrid;
foreach (var item in dg.Columns) {
var g = new Grid() { MinWidth = 10 };
g.SetBinding(Grid.WidthProperty, new System.Windows.Data.Binding("ActualWidth") { Source = item }); // dhHeadName DataGridColumn
var t = new TextBox() { Margin = new Thickness(1, 0, 1, 0), Background = new SolidColorBrush(Color.FromRgb(200, 200, 200)), FontWeight = FontWeights.Bold, FontSize = 9, IsReadOnly = true };
t.Text = "Coucou";
g.Children.Add(t);
((Panel)AssociatedObject).Children.Add(g);
}
}
protected override void OnDetaching() {
base.OnDetaching();
}
}
This is working:
<StackPanel Grid.ColumnSpan="2" Grid.Row="1" Name="pnlDgSubFooter" HorizontalAlignment="Left" Orientation="Horizontal" Margin="-20, 0, 0, 0">
<i:Interaction.Behaviors>
<Classes:BehaviorWithCommand LeDataGrid="{Binding ., ElementName=dgMain}" LeGroupe="{Binding .}" />
</i:Interaction.Behaviors>
</StackPanel>
It's just that designer don't resolve it.
Regards.
Requirement:
Need to display an error message when the user types a forlder name that doesn't exist as shown below:
Problem: I am able to display the UI but not able to call a method in the view model when the user clicks on the button "CreateNew"
View Model Code:
public string this[string columnName]
{
get { return "The entered folder name doesn't exist."; }
}
RelayCommand createNewFolder;
public RelayCommand CreateNewFolder
{
get
{
if (createNewFolder == null)
createNewFolder = new RelayCommand(param => this.OnCreateNewFolder());
return createNewFolder;
}
}
public void OnCreateNewFolder()
{
MessageBox.Show("CreateNewFolder");
}
RelayCommand.cs can be downloaded at: http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mag200902MVVM&DownloadId=4357
Xaml Code:
<Window.Resources>
<ControlTemplate x:Key="validationTemplate">
<DockPanel LastChildFill="True">
<Border Margin="5,5,0,0" DockPanel.Dock="Bottom" Background="Red">
<StackPanel>
<TextBlock Name="ErrorText" Foreground="White" Background="Red"
FontSize="12" Padding="2" FontFamily="Trebuchet MS"
TextWrapping="Wrap"
Text="{Binding [0].ErrorContent}" ></TextBlock>
<StackPanel Margin="0" Orientation="Horizontal">
<Button Content="Create New" Command="{Binding Path=CreateNewFolder}" Margin="10" Padding="5"></Button>
<Button Content="Cancel" Margin="10" Padding="5" ></Button>
</StackPanel>
</StackPanel>
</Border>
<AdornedElementPlaceholder Name="ErrorTextBox" />
</DockPanel>
</ControlTemplate>
<Style x:Key="ValidationStyle" TargetType="{x:Type ComboBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BitmapEffect">
<Setter.Value>
<BitmapEffectGroup>
<OuterGlowBitmapEffect GlowColor="Red" GlowSize="3" Noise="0.6"></OuterGlowBitmapEffect>
</BitmapEffectGroup>
</Setter.Value>
</Setter>
<Setter Property="DataContext"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=DataContext}">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<AdornerDecorator >
<ComboBox IsEditable="True" FontSize="11" Margin="10" Width="250"
VerticalAlignment="Center"
Text="{Binding Path=StrText, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplate}"
Style="{StaticResource ValidationStyle}"></ComboBox>
</AdornerDecorator>
</Grid>
Please note that i set the DataContext property in the style:
<Setter Property="DataContext" Value="{Binding RelativeSource={x:Static
RelativeSource.Self},Path=DataContext}">
</Setter>
Please let me know how to bind the method to a button in the validation template.
You could reference the DataContext for the AdornerDecorators Child in the Binding. I think something like this will work
<Button Content="Create New"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type AdornerDecorator}},
Path=Child.DataContext.CreateNewFolder}"
Margin="10" Padding="5"></Button>
This line looks suspicious:
createNewFolder = new RelayCommand(param => this.OnCreateNewFolder());
Maybe you should replace it by:
createNewFolder = new RelayCommand(OnCreateNewFolder);