代码之家  ›  专栏  ›  技术社区  ›  Nicholas Pappas

在画布周围移动ListBoxItem?

  •  0
  • Nicholas Pappas  · 技术社区  · 14 年前

    我正致力于在画布周围拖动对象,画布封装在ListBoxItems中——其效果是创建一个简单的伪桌面。

    我有一个列表框,其中画布作为itemspaneltempalte,以便列表框项可以显示在屏幕上的任何位置:

    <ListBox ItemsSource="{Binding Windows}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
    

    我有一个样式来定义ListBoxItem的显示方式:

    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
        <Setter Property="Canvas.Left" Value="{Binding Left, Mode=TwoWay}" />
        <Setter Property="Canvas.Top" Value="{Binding Top, Mode=TwoWay}" />
        <Setter Property="OverridesDefaultStyle" Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <local:PseudoWindowContainer Content="{TemplateBinding Content}" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    “伪窗口容器”从ContentControl扩展而来,并应用了自己的样式,使其看起来像一个对话框(标题栏、关闭按钮等)。这里有一大块:

      <Style TargetType="{x:Type local:PseudoWindowContainer}">
    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    <Setter Property="Width" Value="{Binding Width, Mode=TwoWay}" />
    <Setter Property="Height" Value="{Binding Height, Mode=TwoWay}" />
    <Setter Property="OverridesDefaultStyle" Value="True" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:PseudoWindowContainer}">
          <Grid Name="LayoutRoot" Background="White">
            <!-- ... snip ... -->
                <Border Name="PART_TitleBar" Grid.Row="0" Background="LightGray" CornerRadius="2,2,0,0" VerticalAlignment="Stretch" Cursor="Hand" />
                <TextBlock Name="TitleBar_Caption" Text="{Binding DisplayName}" Grid.Row="0" Background="Transparent" Padding="5,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" />
                <Button Name="TitleBar_CloseButton" Command="{Binding CloseCommand}" Grid.Row="0" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,5,5,0" Width="20" Height="20" Cursor="Hand" Background="#FFFF0000" Foreground="#FF212121" />
                <!-- ContentPresenter -->
                <ContentPresenter Grid.Row="1" />
            <!-- ... snip ... -->
          </Grid>
          <ControlTemplate.Triggers>
            <Trigger Property="IsSelected" Value="True">
              <Setter TargetName="WindowBorder" Property="Background" Value="Blue" />
            </Trigger>
            <Trigger Property="IsSelected" Value="False">
              <Setter TargetName="WindowBorder" Property="Background" Value="#22000000" />
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
    

    在pseudowindowcontainer.cs类中,我创建一些事件处理程序来侦听mousedown/mouseup/movemove事件:

    public override void OnApplyTemplate()
    {
      _titleBar = (Border)Template.FindName("PART_TitleBar", this);
      if (_titleBar != null)
      {
        _titleBar.MouseDown += TitleBar_MouseDown;
        _titleBar.MouseUp += TitleBar_MouseUp;
      }
    
      _grip = (ResizeGrip)Template.FindName("PART_ResizeGrip", this);
      if (_grip != null)
      {
        _grip.MouseLeftButtonDown += ResizeGrip_MouseLeftButtonDown;
        _grip.MouseLeftButtonUp += ResizeGrip_MouseLeftButtonUp;
      }
    
      base.OnApplyTemplate();
    }
    
    private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
    {
      _titleBar.MouseMove += TitleBar_MouseMove;
      ((Border)sender).CaptureMouse();
    
      _windowLocation.X = Left;
      _windowLocation.Y = Top;
    
      _clickLocation = this.PointToScreen(Mouse.GetPosition(this));
    }
    
    private void TitleBar_MouseUp(object sender, MouseButtonEventArgs e)
    {
      _titleBar.MouseMove -= TitleBar_MouseMove;
      ((Border)sender).ReleaseMouseCapture();
    }
    
    private void TitleBar_MouseMove(object sender, MouseEventArgs e)
    {
      Point currentLocation = this.PointToScreen(Mouse.GetPosition(this));
    
      Left = _windowLocation.X + currentLocation.X - _clickLocation.X;
      Top = _windowLocation.Y + currentLocation.Y - _clickLocation.Y;
    }
    

    我遇到的问题是“左”和“上”没有定义属性,并且更新到canvas.setleft/settop(或getleft/gettop,相应地)不会更新canvas上的位置。

    我在所放置控件的视图模型中定义了“左”和“上” 进入之内 然后,由于模板的原因,用一个伪窗口容器包装ListBoxItem和。当应用程序最初出现时,这些值会得到尊重,对象会出现在正确的位置。

    我相信我需要在我的伪窗口容器(又称:ContentControl)中定义“左”和“上”,并让它们传播回我的视图模型。这有可能吗?

    再次感谢您的帮助!

    2 回复  |  直到 14 年前
        1
  •  1
  •   Nicholas Pappas    14 年前

    我找到了解决这个问题的办法。我不再把它全部输入,而是指向描述我所做的事情的msdn论坛帖子: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/d9036b30-bc6e-490e-8f1e-763028a50153

        2
  •  0
  •   zendar    14 年前

    你读过Bea Stollnitz的文章吗: The power of Styles and Templates in WPF ?
    这是一个列表框的例子,其中的项是在转换器中计算的特定坐标下绘制的。