2016-10-14 9 views
0

Currentlly создает мое приложение Windows 10, и я пытаюсь переместить прямоугольник на холсте, следуя шаблону mvvm. Код ниже работает, но я сломал mvvm, используя uielemnt в моей viewmodel PointerDragEvent.Получение выбранных ItemsControl Item

Dim rec = TryCast(e.OriginalSource, Button) 
    Dim selrecitem = TryCast(rec.DataContext, RectItem) 

Вопрос

Есть не Hacky/правильный способ сделать это?

Как получить элемент, который я нажимаю, и передать его в мою модель просмотра?

Все элементы на холсте будут динамически создаваться.

<Page 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="using:App11" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core" 
x:Class="App11.MainPage" 
mc:Ignorable="d"> 

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <Grid.DataContext> 
     <local:myviewmodel/> 
    </Grid.DataContext> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*"/> 
     <RowDefinition Height="8*"/> 
     <RowDefinition Height="*"/> 

    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="11*"/> 
     <ColumnDefinition Width="*"/> 
    </Grid.ColumnDefinitions> 
    <ItemsControl x:Name="itemsControl" Grid.Column="1" Grid.Row="1" ItemsSource="{Binding myrectangles, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> 
     <Interactivity:Interaction.Behaviors> 
      <Core:EventTriggerBehavior EventName="ManipulationDelta"> 
       <Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerDrag"/> 
      </Core:EventTriggerBehavior> 
     </Interactivity:Interaction.Behaviors> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <Canvas Background="White"> 

       </Canvas> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 

     <ItemsControl.ItemTemplate> 

      <DataTemplate> 
       <Button x:Name="PageItem" Background="Transparent" BorderBrush="DodgerBlue" Width="{Binding Width}" Height="{Binding Height}" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Command="{Binding SendMyDC, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" > 
        <Button.RenderTransform> 
         <CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/> 
        </Button.RenderTransform> 

       </Button> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 

</Grid> 

ViewModel

Public Class myviewmodel 
Implements INotifyPropertyChanged 
Private Sub NotifyPropertyChanged(Optional propertyName As String = "") 
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) 
End Sub 

Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 
Private _myrectangles As New ObservableCollection(Of RectItem) 
Public Property myrectangles As ObservableCollection(Of RectItem) 
    Get 
     Return _myrectangles 
    End Get 
    Set(value As ObservableCollection(Of RectItem)) 
     _myrectangles = value 
     NotifyPropertyChanged() 
    End Set 
End Property 

Public Sub New() 
    Dim newrect As New RectItem 
    newrect.Height = 100 
    newrect.Width = 150 
    newrect.X = 50 
    newrect.Y = 50 
    _myrectangles.Add(newrect) 
End Sub 

Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs) 
    Dim dx_point = e.Delta.Translation.X 
    NotifyPropertyChanged() 
    Dim dy_point = e.Delta.Translation.Y 
    NotifyPropertyChanged() 
    Dim rec = TryCast(e.OriginalSource, Button) 
    Dim selrecitem = TryCast(rec.DataContext, RectItem) 

    selrecitem.X += dx_point 
    selrecitem.Y += dy_point 
End Sub 
End Class 

RectItemClass

Public Class RectItem 
Implements INotifyPropertyChanged 
Private Sub NotifyPropertyChanged(Optional propertyName As String = "") 
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) 
End Sub 

Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 

Public Property X As Double 
    Get 
     Return m_X 
    End Get 
    Set 
     m_X = Value 
     NotifyPropertyChanged() 
    End Set 
End Property 
Private m_X As Double 
Public Property Y As Double 
    Get 
     Return m_Y 
    End Get 
    Set 
     m_Y = Value 
     NotifyPropertyChanged() 
    End Set 
End Property 
Private m_Y As Double 
Public Property Width As Double 
    Get 
     Return m_Width 
    End Get 
    Set 
     m_Width = Value 
     NotifyPropertyChanged() 
    End Set 
End Property 
Private m_Width As Double 
Public Property Height As Double 
    Get 
     Return m_Height 
    End Get 
    Set 
     m_Height = Value 
     NotifyPropertyChanged() 
    End Set 
End Property 
Private m_Height As Double 
End Class 

Редактировать # 1 Вместо того чтобы использовать элемент управления элемента я использовал ListView/Listbox и переплетены выбранный элемент к собственность в моем vewimodel. В представлении списка есть некоторая проблема с тем, чтобы объект презентации был выровнен с представленным элементом и со списком, событие-указатель не срабатывает.

<ListView x:Name="itemsControl" Grid.Column="1" Grid.Row="1" ItemsSource="{Binding myrectangles, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Background="#FFF2F2F2" SelectedItem="{Binding selectedrec, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> 

     <Interactivity:Interaction.Behaviors> 
      <Core:EventTriggerBehavior EventName="ManipulationDelta"> 
       <Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerDrag"/> 
      </Core:EventTriggerBehavior> 
      <Core:EventTriggerBehavior EventName="PointerPressed"> 
       <Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="PointerPressed"/> 
      </Core:EventTriggerBehavior> 
      <!--<Core:EventTriggerBehavior EventName="PointerReleased"> 
       <Core:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="Up"/> 
      </Core:EventTriggerBehavior>--> 
     </Interactivity:Interaction.Behaviors> 



     <ListView.ItemsPanel> 
      <ItemsPanelTemplate> 
       <Canvas Background="White"> 

       </Canvas> 
      </ItemsPanelTemplate> 
     </ListView.ItemsPanel> 
     <!--<ListView.ItemContainerStyle> 
      <Style TargetType="ListViewItem"> 

       <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate> 
          <ContentPresenter/> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 


      </Style> 
     </ListView.ItemContainerStyle>--> 
     <ListView.ItemTemplate> 

      <DataTemplate> 
       <Rectangle x:Name="PageItem" Width="{Binding Width}" Height="{Binding Height}" Fill="Transparent" Stroke="DodgerBlue" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" > 


        <Rectangle.RenderTransform> 
         <CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/> 
        </Rectangle.RenderTransform> 

       </Rectangle> 

      </DataTemplate> 
     </ListView.ItemTemplate> 
    </ListView> 

</Grid> 

Обновлено ViewModel

Public _selectedrec As New RectItem 
Public Property selectedrec As RectItem 
    Get 
     Return _selectedrec 
    End Get 
    Set(value As RectItem) 
     _selectedrec = value 
     NotifyPropertyChanged() 
    End Set 
End Property 

Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs) 

    Dim dx_point = e.Delta.Translation.X 
    NotifyPropertyChanged() 
    Dim dy_point = e.Delta.Translation.Y 
    NotifyPropertyChanged() 


    selectedrec.X += dx_point 
    NotifyPropertyChanged() 
    selectedrec.Y += dy_point 
    NotifyPropertyChanged() 



End Sub 

Пример проблем

Нет ItemContainerStyle - При попытке перетащить объект привязывается к 0,0 холста

enter image description here

MyHalfFix - раскомментируйте ItemContainerStyle - все работает правильно, что им стремится к

enter image description here

общей проблемы при реализации в реальной программе

enter image description here

Красный Item является ведущим listviewitem. Он рисуется правильно, но позиционирование не выравнивается с нарисованным прямоугольником, которое всегда привязывается к точке 0,0 холста. Я могу сделать его прозрачным, но, как вы можете видеть при рисовании прямоугольника, он не соответствует курсору

ответ

0

Вы можете использовать InvokeCommandAction для события ManipulationDelta, чтобы избежать нарушения шаблона MVVM. InvokeCommandAction может передать параметр viewmodel, и мы можем передать selecteditem по параметру.Объектом ManipulationDelta должна быть кнопка вместо ItemsControl, а InvokeCommandAction будет работать, то, что вы на самом деле перетаскиваете, является самой кнопкой. Обновленный код следующим образом:

XAML

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Name="root"> 
    ... 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Button x:Name="PageItem" Background="Transparent" BorderBrush="DodgerBlue" Width="{Binding Width}" Height="{Binding Height}" ManipulationMode="TranslateX, TranslateY" IsHitTestVisible="{Binding IsChecked, ElementName=SelectToolButton, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" > 
        <Interactivity:Interaction.Behaviors> 
         <Core:EventTriggerBehavior EventName="ManipulationDelta" SourceObject="{Binding ElementName=PageItem}"> 
          <Core:InvokeCommandAction Command="{Binding DataContext.SendMyDC, ElementName=root}" CommandParameter="{Binding}"></Core:InvokeCommandAction> 
          <Core:CallMethodAction TargetObject="{Binding DataContext, ElementName=root, Mode=OneWay}" MethodName="PointerDrag" /> 
         </Core:EventTriggerBehavior> 
        </Interactivity:Interaction.Behaviors> 
        <Button.RenderTransform> 
         <CompositeTransform TranslateX="{Binding X}" TranslateY="{Binding Y}"/> 
        </Button.RenderTransform> 
       </Button> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Grid> 

myviewmodel

Public Class myviewmodel 
... 
Private m_sendCommand As IDelegateCommand 
Public Property SendMyDC As IDelegateCommand 
    Get 
     Return m_sendCommand 
    End Get 
    Protected Set(value As IDelegateCommand) 
     m_sendCommand = value 
    End Set 
End Property 

Public Sub New() 
    Me.SendMyDC = New DelegateCommand(AddressOf ExecuteSendMyDC) 
    Dim newrect As New RectItem 
    newrect.Height = 100 
    newrect.Width = 150 
    newrect.X = 50 
    newrect.Y = 50 
    _myrectangles.Add(newrect) 
End Sub 

Dim selrecitem As RectItem 
Public Sub PointerDrag(sender As Object, e As ManipulationDeltaRoutedEventArgs) 
    Dim dx_point = e.Delta.Translation.X 
    NotifyPropertyChanged() 
    Dim dy_point = e.Delta.Translation.Y 
    NotifyPropertyChanged() 
    'Dim rec = TryCast(e.OriginalSource, Button) 
    'Dim selrecitem = TryCast(rec.DataContext, RectItem) 
    If selrecitem IsNot Nothing Then 
     selrecitem.X += dx_point 
     selrecitem.Y += dy_point 
    End If 
End Sub 

Private Sub ExecuteSendMyDC(param As Object) 
    selrecitem = CType(param, RectItem) 
End Sub 
End Class 

DelegateCommand класс

Public Class DelegateCommand 
Implements IDelegateCommand 
Private _execute As Action(Of Object) 
Private _canExecute As Func(Of Object, Boolean) 
#Region "Constructors" 
Public Sub New(execute As Action(Of Object), canExecute As Func(Of Object, Boolean)) 
    Me._execute = execute 
    Me._canExecute = canExecute 
End Sub 
Public Sub New(execute As Action(Of Object)) 
    Me._execute = execute 
    Me._canExecute = AddressOf Me.AlwaysCanExecute 
End Sub 
#End Region 
#Region "IDelegateCommand" 
Private Function AlwaysCanExecute(param As Object) As Boolean 
    Return True 
End Function 
Public Function CanExecute(parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute 
    Return _canExecute(parameter) 
End Function 
Public Event CanExecuteChanged(sender As Object, e As EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged 
Public Sub Execute(parameter As Object) Implements System.Windows.Input.ICommand.Execute 
    _execute(parameter) 
End Sub 

Public Sub RaiseCanExecuteChanged() Implements IDelegateCommand.RaiseCanExecuteChanged 
    RaiseEvent CanExecuteChanged(Me, EventArgs.Empty) 
End Sub 
#End Region 
End Class 
Public Interface IDelegateCommand 
    Inherits ICommand 
    Sub RaiseCanExecuteChanged() 
End Interface 

DelegateCommand является общий класс для вас в дальнейшем ссылаться другие команды. Более подробно просьба обращаться к Command binding inside DataTemplate.

+0

Я попытался реализовать ваш код, но он не сработал. Когда я начинаю тащиться, ничего не возникает. Я нашел работу, хотя я обновлю вопрос – Twinnaz

+0

@Twinnaz Я загрузил завершенную демоверсию, в которой я хорошо тестировал [github] (https://github.com/sunteenwu/PersonalDemo/tree/master/CBInding), вы можете если у вас есть вопросы, пожалуйста, сообщите мне. –

+0

Он хорошо работает в примере, который я вам предоставил. К сожалению, он не работает во всей программе, пытающейся ее реализовать. Кнопка будет динамически рисоваться. Я могу предоставить код, но я думаю, что его слишком много, чтобы публиковать здесь. – Twinnaz

Смежные вопросы