2

Based on a project from the answer to this question:

Graph nodes coordinates evaluation

and using the MVVM Light Toolkit I'm trying to develop an application that would allow the user not only to move items all around the canvas, but also resize them. Here is what I have so far:

http://screenshooter.net/4766406/tfcqpjw

Main Window XAML

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication2"
    xmlns:localvm="clr-namespace:WpfApplication2.ViewModel"
    Title="MainWindow" Height="350" Width="927.985" x:Name="view">
<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="EditorStyles.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>
<DockPanel>
    <StackPanel Width="95" DockPanel.Dock="Left" Margin="5,0,0,0">
        <local:ButtonsPanel/>
    </StackPanel>
    <Grid Margin="10">
        <Grid.Resources>
            <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
            <CompositeCollection x:Key="Col">
                <CollectionContainer Collection="{Binding DataContext.Notes,Source={x:Reference view}}"/>
            </CompositeCollection>
            <DataTemplate DataType="{x:Type localvm:NoteViewModel}">
                <Grid>
                    <Thumb DragDelta="Thumb_Drag"
                       IsEnabled="{Binding IsSelected,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
                        <Thumb.Template>
                            <ControlTemplate TargetType="Thumb">
                                <Canvas>
                                    <Path Fill="#FFAA0000" Data="{Binding ShapeGeometry}" Stretch="Fill" x:Name="Path"/>
                                </Canvas>
                                <ControlTemplate.Triggers>
                                    <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True">
                                        <Setter TargetName="Path" Property="Fill" Value="Red"/>
                                    </DataTrigger>
                                    <Trigger Property="IsDragging" Value="True">
                                        <Setter TargetName="Path" Property="Fill" Value="Green"/>
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Thumb.Template>
                    </Thumb>                        
                </Grid>                    
            </DataTemplate>
        </Grid.Resources>

        <ListBox SelectedItem="{Binding SelectedNote}" 
                 PreviewMouseMove="ListBox_PreviewMouseMove"
                 PreviewMouseDown="ListBox_PreviewMouseDown">
            <ListBox.Template ... > <!-- Collapsed -->
            </ListBox.Template>
            <ListBox.ItemsSource>
                <StaticResource ResourceKey="Col"/>
            </ListBox.ItemsSource>
            <ListBox.ItemsPanel ...> <!-- Collapsed -->
            </ListBox.ItemsPanel>
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <!-- Moves the object -->
                    <Setter Property="Canvas.Left" Value="{Binding X}"/>
                    <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ListBoxItem">
                                <ContentPresenter x:Name="Content"/>                                    
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
    </Grid>
</DockPanel>

Thumb's DragDelta from the MainWindow code behind + the constructor:

public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }

    private void Thumb_Drag(object sender, DragDeltaEventArgs e)
    {
        var thumb = sender as Thumb;
        if (thumb == null)
            return;

        var note = thumb.DataContext as NoteViewModel;
        if (note == null)
            return;

        note.X += e.HorizontalChange;
        note.Y += e.VerticalChange;
    }

Important properties and methods from the MainViewModel :

public class MainViewModel : ViewModelBase
{
    private ObservableCollection<NoteViewModel> _notes;
    public ObservableCollection<NoteViewModel> Notes
    {
        get { return _notes ?? (_notes = new ObservableCollection<NoteViewModel>()); }
    }

    private NoteViewModel _selectedNote;
    public NoteViewModel SelectedNote {...}

    public MainViewModel()
    {
        _notes = new ObservableCollection<NoteViewModel>(NotesDataSource.GetRandomNotes());
    }

    #region Creating New Notes

    private bool _creatingNewNote;
    public bool CreatingNewNote
    {
        get { return _creatingNewNote; }
        set
        {
            _creatingNewNote = value;
            RaisePropertyChanged("CreatingNewNote");

            if (value)
                CreateNewNote();
            else
                RemoveNewObjects();
        }
    }

    public void CreateNewNote()
    {
        var newnote = new NoteViewModel()
        {
            Name = "Note" + (Notes.Count + 1),
            IsNew = true
        };

        Notes.Add(newnote);
        SelectedNote = newnote;
    }

    public void RemoveNewObjects()
    {
        Notes.Where(x => x.IsNew).ToList().ForEach(x => Notes.Remove(x));
    }
    #endregion
}

NoteViewModel:

public class NoteViewModel : ViewModelBase
{        
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            RaisePropertyChanged("Name");
        }
    }

    #region Coordinates & Size
    private double _x;
    public double X { ...}

    private double _y;
    public double Y {...}

    private double _width;
    public double Width {...}

    private double _height;
    public double Height {...}
    #endregion

    #region Shape Geometry
    private string _shapeGeometry;
    public string ShapeGeometry {...}
    #endregion

    #region Selection Properties
    private bool _isNew;
    public bool IsNew {...}
    #endregion

    public NoteViewModel()
    {      
        Random random = new Random();
        var notenumber = random.Next(0, 100);
        var notename = "Note" + notenumber;            
        Name = notename;
        X = 10;
        Y = 10;
        ShapeGeometry = "M39.967 23.133c-0.211 0.189-0.523 0.199-0.748 0.028l-7.443-5.664l-3.526 21.095c-0.013 0.08-0.042 0.153-0.083 0.219  c-0.707 3.024-4.566 5.278-9.104 5.278c-5.087 0-9.226-2.817-9.226-6.28s4.138-6.281 9.226-6.281c2.089 0 4.075 0.466 5.689 1.324  l4.664-26.453c0.042-0.242 0.231-0.434 0.475-0.479c0.237-0.041 0.485 0.068 0.611 0.28l9.581 16.192  C40.227 22.637 40.178 22.945 39.967 23.133z";
        Width = CalculateSize("w");
        Height = CalculateSize("h");
    }

    private double CalculateSize(string s) {...}

The Thumb allows for moving, and I was trying to combine the above with the example from here (without Adorners, they look awfully complicated, as all the other examples I found): http://www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part

However, after racking my brains for a considerably long time, I didn't manage to figure out a workable solution. How can I make my items resize? Please, help a damsel in distress!

Community
  • 1
  • 1
SG_90
  • 195
  • 3
  • 14

0 Answers0