我正在研究在Canvas周围拖动对象,这些对象封装在ListBoxItems中 - 效果是创建一个简单的伪桌面。
我有一个带有Canvas的ListBox作为ItemsPanelTempalte,因此ListBoxItems可以出现在屏幕上的任何位置:
<ListBox ItemsSource="{Binding Windows}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
我有一个Style来定义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,使其看起来像一个对话框(标题栏,关闭按钮等......)。这是它的一大块:
<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上的位置。
我在中将放入 ListBoxItems的控件的ViewModel中定义了“Left”和“Top”,因此随后由于模板而被PseudoWindowContainer包装。这些值得到兑现,当应用程序最初出现时,对象确实出现在正确的位置。
我相信我需要以某种方式在我的PseudoWindowContainer(又名:ContentControl)中定义“Left”和“Top”,并让它们传播回我的ViewModel。这可能吗?
再次感谢您的帮助!
答案 0 :(得分:1)
我找到了问题的解决方案。而不是再次输入,我将指向描述我所做的MSDN论坛帖子: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/d9036b30-bc6e-490e-8f1e-763028a50153
答案 1 :(得分:0)
你读过Bea Stollnitz的文章:The power of Styles and Templates in WPF吗? 这是Listbox的一个示例,其中项目是在Converter中计算的特定坐标处绘制的。