WPF中的可拖动对象在ItemsControl中如何实现?

5

我希望能够实现一个可拖动项目的ItemsControl。使用ItemsControl的原因是我可以在后台绑定到我的ViewModel。

我尝试在Canvas中使用Thumb控件,它运行得很完美,但是一旦将其放入ItemsControl中,它就无法正常工作。这是我尝试过的:

        <ItemsControl ItemsSource="{Binding MyItems}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Thumb Canvas.Left="0" Canvas.Top="0" Width="50" Height="50" DragDelta="MyThumb_DragDelta"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

    </ItemsControl>

代码背后:

    public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DataContext = new MainViewModel();
    }

    private void MyThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
    {
        Canvas.SetLeft((UIElement)sender, Canvas.GetLeft((UIElement)sender) + e.HorizontalChange);
        Canvas.SetTop((UIElement)sender, Canvas.GetTop((UIElement)sender) + e.VerticalChange);
    }

最后是我的ViewModel:

    public class MainViewModel : DependencyObject 
{
    public ObservableCollection<Note> MyItems { get; set;}


    public MainViewModel()
    {
        MyItems = new ObservableCollection<Note>();
        MyItems.Add(new Note(){Name="test"});
    }

}

public class Note : INotifyPropertyChanged 
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string name;

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            if(PropertyChanged!=null) PropertyChanged(this,new PropertyChangedEventArgs("Name"));
        }
    }


}

当我在窗口上执行以下操作时,它可以正常工作:
  <Canvas>
        <Thumb Canvas.Left="0" Canvas.Top="0" Width="50" Height="50" DragDelta="MyThumb_DragDelta"/>            
    </Canvas>

但是,当我在ItemsControl中使用它时,它不再起作用。我猜测ItemsControl正在注册鼠标事件并覆盖Thumb?

有没有好的解决方案可以让它正常工作?

2个回答

10

一开始,我认为Ben的方法不起作用,但经过更多的实验,我终于成功了。

问题可以概括为:当处于项控件中时,Canvas.Top和Canvas.Left无法工作。但你是正确的,样式是解决问题的途径。下面是我想出的解决方案:

<ItemsControl ItemsSource="{Binding Notes}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Thumb Width="150" Height="150" DragDelta="Thumb_DragDelta" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Left" Value="{Binding X}" />
                <Setter Property="Canvas.Top" Value="{Binding Y}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

而且代码后台:

 public partial class MainWindow : Window
{
    public ObservableCollection<Note> Notes { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        DataContext = this;

        Notes = new ObservableCollection<Note>();
        Notes.Add(new Note(){Title="test", X=100, Y=0});
    }

    private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
    {
        Note n = (Note)((FrameworkElement)sender).DataContext;
        n.X += e.HorizontalChange;
        n.Y += e.VerticalChange;
    }
}

public class Note : INotifyPropertyChanged
{
    private string title;
    private double x;
    private double y;

    public double Y
    {
        get { return y; }
        set
        {
            y = value;
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Y"));
        }
    }

    public double X
    {
        get { return x; }
        set
        {
            x = value;
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("X"));
        }
    }


    public string Title
    {
        get { return title; }
        set
        {
            title = value;
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Title"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

谢谢!我已经试图弄清楚DragDelta将近一个星期了!你救了我的项目!但愿我早点发现这篇文章。 - master_ruko

1

尝试通过样式设置Canvas绑定属性

<Style x:Key="ThumbStyle">
  <Setter Property="Canvas.Left" Value="{Binding Path=Left}"/>
  <Setter Property="Canvas.Top" Value="{Binding Path=Top}"/>
  <!-- more if required -->

</Style>

然后拇指变成:

<Thumb Style={StaticResource ThumbStyle}" ... />


谢谢回复,但似乎仍然存在同样的问题。就像在itemscontrol中canvas无法工作一样。事件正在触发,我正在设置属性以在canvas上移动它。 - Kelly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接