Reputation: 108
So I'm using mvvm to bind some elements in an item control witch has a canvas in the ItemsPanel. I want to change Canvas.Top and Left of the elements inside itemsControl when ever it's clicked. xaml file:
<ItemsControl ItemsSource="{Binding Elements}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Top" Value="{Binding Y}" />
<Setter Property="Canvas.Left" Value="{Binding X}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle MouseLeftButtonDown="ChangeLocation" Width="50" Height="50"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and here's my viewModel
private double _X;
public double X
{
get
{
return _X;
}
set
{
_X= value;
OnPropertyChanged(nameof(_X));
}
}
private double _Y;
public double Y
{
get
{
return _Y;
}
set
{
_Y= value;
OnPropertyChanged(nameof(_Y));
}
}
and listing viewModel
public IEnumerable<ElementViewModel> Elements => _elements;
public ObservableCollection<ElementViewModel> _elements { get; set; }
public ElementListingViewModel()
{
//GetElements
}
So I tried this to change the top and left of the element that get clicked:
private void ChangeLocation(object sender, MouseEventArgs e)
{
Canvas.SetLeft(sender as Rectangle, 200);
Canvas.SetTop(sender as Rectangle,, 200);
}
but this doesn't work and also you can't use any of Canvas static methods. Maybe it's because you can't use Canvas methods in ItemsControl, but I set a canvas in the ItemsPanel. So,this ItemControl and canvas should do the same, but it doesn't. what should I do?
Upvotes: -1
Views: 135
Reputation: 128061
You could set the ChangeLocation event handler by an EventSetter
in the ItemContainerStyle. The Bindings must also be TwoWay
in order to update the view model when the view changes.
<ItemsControl ItemsSource="{Binding Elements}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X, Mode=TwoWay}" />
<Setter Property="Canvas.Top" Value="{Binding Y, Mode=TwoWay}" />
<EventSetter Event="MouseLeftButtonDown" Handler="ChangeLocation"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="50" Height="50" Fill="Red"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The sender
of the event is a ContentPresenter
:
private void ChangeLocation(object sender, MouseButtonEventArgs e)
{
var cp = (ContentPresenter)sender;
Canvas.SetLeft(cp, 200);
Canvas.SetTop(cp, 200);
}
Besides that, you must notify about the change of a property, not its backing field:
OnPropertyChanged(nameof(X)); // not nameof(_X)
OnPropertyChanged(nameof(Y)); // not nameof(_Y)
The Elements
property in the main view model could be declared simpler. There is no need for two public properties.
public ObservableCollection<ElementViewModel> Elements { get; }
= new ObservableCollection<ElementViewModel>();
Upvotes: 1