Danial
Danial

Reputation: 108

Edit the canvas.Top and Left in itemsControlTemplate wpf

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

Answers (1)

Clemens
Clemens

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

Related Questions