Перемещение ListBoxItems вокруг холста? - PullRequest
0 голосов
/ 07 августа 2010

Я работаю над перетаскиванием объектов вокруг Canvas, которые инкапсулированы в ListBoxItems - эффект заключается в создании простого псевдо рабочего стола.

У меня есть ListBox с Canvas в качестве ItemsPanelTempalte, так чтоListBoxItems могут появляться в любом месте экрана:

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

У меня есть Стиль, чтобы определить, как должны выглядеть ListBoxItems:

<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>

«PseudoWindowContainer» выходит из 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;
}

Проблема, с которой я сталкиваюсь, заключается в том, что «Left» и «Top» не являются определенными свойствами, и их обновление до Canvas.SetLeft / SetTop (или соответственно GetLeft / GetTop) не обновляет позицию на Canvas.

У меня есть «Left» и «Top», определенные в ViewModel элементов управления, которые я помещаю в ListBoxItems, и, таким образом, впоследствии оборачиваем PseudoWindowContainer из-за шаблона.Эти значения соблюдаются, и объекты появляются в правильном месте, когда приложение приходит изначально.

Я считаю, что мне нужно как-то определить «Left» и «Top» в моем PseudoWindowContainer (aka: ContentControl) и иметьони распространяются обратно до моей ViewModel.Возможно ли это?

Еще раз спасибо за любую помощь!

Ответы [ 2 ]

1 голос
/ 09 августа 2010

Я нашел решение проблемы.Вместо того, чтобы вводить все заново, я укажу на сообщение на форуме MSDN, в котором описано, что я сделал: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/d9036b30-bc6e-490e-8f1e-763028a50153

0 голосов
/ 07 августа 2010

Читали ли вы статью Беа Столльниц: Сила стилей и шаблонов в WPF ?
Это пример списка, где элементы рисуются с определенными координатами, рассчитанными в Конвертере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...