我正在尝试使用WPF(第一次使用wpf)为学校项目(2D Multiplayer-PacMan)实现某种相机逻辑。我们有一个使用Canvas和ItemControl的基于Tile的Walkmap,它比实际的屏幕尺寸大:
GameView.xaml
<controls:Camera HorizontalOffset="{Binding xPos}" VerticalOffset="{Binding yPos}">
<ItemsControl ItemsSource="{Binding Tiles}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding ImagePath}" Width="{Binding Size}" Height="{Binding Size}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</controls:Camera>
我正在尝试将ScrollViewer用于我的相机,但是众所周知,由于它们是只读的,我们无法将水平和垂直偏移绑定到属性。 这就是为什么我创建一个名为“Camera”的UserControl,它有一个ScrollViewer和两个DependencyProperties用于绑定。
Camera.xaml
<UserControl x:Class="PacmanClient.UserControls.Camera"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PacmanClient.UserControls"
mc:Ignorable="d"
d:DesignHeight="1600" d:DesignWidth="1900">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<ScrollViewer Name="cameraViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" IsEnabled="True">
<ContentPresenter/>
</ScrollViewer>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Camera.xaml.cs
public partial class Camera : UserControl
{
ScrollViewer cameraViewer;
public Camera()
{
InitializeComponent();
}
#region HorizontalOffset
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
cameraViewer = this.Template.FindName("cameraViewer", this) as ScrollViewer;
}
public double HorizontalOffset
{
get
{
return (double)GetValue(HorizontalOffsetProperty);
}
set
{
SetValue(HorizontalOffsetProperty, value);
OnHorizontalOffsetChanged(value);
}
}
public static readonly DependencyProperty HorizontalOffsetProperty =
DependencyProperty.RegisterAttached("HorizontalOffset", typeof(double), typeof(Camera),
new UIPropertyMetadata(0.0));
private void OnHorizontalOffsetChanged(double value)
{
cameraViewer.ScrollToHorizontalOffset(value);
}
#endregion
#region VerticalOffset
public double VerticalOffset
{
get
{
return (double)GetValue(VerticalOffsetProperty);
}
set
{
SetValue(VerticalOffsetProperty, value);
OnVerticalOffsetChanged(value);
}
}
public static readonly DependencyProperty VerticalOffsetProperty =
DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(Camera),
new UIPropertyMetadata(0.0));
private void OnVerticalOffsetChanged(double value)
{
cameraViewer.ScrollToVerticalOffset(value);
}
#endregion
}
现在我有两个问题。 第一: 当我试图使用我的UserControl(如GameView.xaml中所见)并将一些属性绑定到DependencyProperties时,我得到的错误是那些成员无法识别或无法访问。(我实际上认为我修复了这个,但现在又回来了。)这必须是一个AccessProblem,因为自动完成实际上建议我使用HorinzontalOffset和VerticalOffset。 我只是找不到解决方案。
第二: 在我能够访问这些属性并成功将某些属性绑定到它们的版本中,当绑定到它们的属性发生更改时,DependencyProperties的值永远不会更改。我通过调试检查它,并且永远不会调用后面的代码设置器。
我希望你能帮我解决这些问题,我不知道为什么它不起作用。
[编辑]
MainWindow.Xaml
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication3"
xmlns:test="clr-namespace:test"
mc:Ignorable="d"
Title="MainWindow" Height="1600" Width="1900">
<StackPanel>
<Button Content="yolo" Click="Button_Click"></Button>
<ScrollViewer Name ="hallo" Height="1600" Width="1600" test:ScrollViewerExtension.HorizontalOffset = "{Binding xPos}" test:ScrollViewerExtension.VerticalOffset="{Binding yPos}" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Canvas Height="3000" Width="3000">
<Ellipse Name="e1" Height="42" Width="42" Fill="Yellow"></Ellipse>
</Canvas>
</ScrollViewer>
</StackPanel>
</Window>
Mainwindow.cs
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public double xPos
{
get;
set;
}
public double yPos
{
get;
set;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
xPos += 50.0;
yPos += 50.0;
Canvas.SetTop(e1, yPos);
Canvas.SetLeft(e1, xPos);
}
}
}
答案 0 :(得分:0)
好吧,让我们看看这对你有帮助。如果没有看到完整的代码,你的第一个问题很难解决,因为你在这里展示的内容没有任何问题(事实上,我制作了一个测试解决方案,复制/粘贴这段代码并且有效)。
第二个问题与您如何定义附加属性有关。
在RegisterAttached的第三个参数中,您应该向propertyChanged事件处理方法添加一个回调,如下所示:
public static readonly DependencyProperty HorizontalOffsetProperty =
DependencyProperty.RegisterAttached("HorizontalOffset", typeof(object), typeof(Camera),new UIPropertyMetadata(null, HorizontalOffsetPropertyChanged));
此外,您还需要添加两种方法来获取/设置此属性值:
public static object GetHorizontalOffset(DependencyObject obj)
{
return (string)obj.GetValue(HorizontalOffsetProperty);
}
public static void SetHorizontalOffset(DependencyObject obj, object value)
{
obj.SetValue(HorizontalOffsetProperty, value);
}
这是您的usercontrol的完整代码:
public partial class Camera : UserControl
{
public Camera()
{
InitializeComponent();
}
#region HorizontalOffset
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
public static readonly DependencyProperty HorizontalOffsetProperty =
DependencyProperty.RegisterAttached("HorizontalOffset", typeof(object), typeof(Camera),new UIPropertyMetadata(null, HorizontalOffsetPropertyChanged));
public static object GetHorizontalOffset(DependencyObject obj)
{
return (string)obj.GetValue(HorizontalOffsetProperty);
}
public static void SetHorizontalOffset(DependencyObject obj, object value)
{
obj.SetValue(HorizontalOffsetProperty, value);
}
public static void HorizontalOffsetPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
Camera cam = o as Camera;
ScrollViewer scroll=cam.Template.FindName("cameraViewer", cam) as ScrollViewer;
double horizontal = 0;
if (e.NewValue is double)
{
horizontal =(double) e.NewValue;
}
scroll.ScrollToHorizontalOffset(horizontal);
}
#endregion
#region VerticalOffset
public static readonly DependencyProperty VerticalOffsetProperty =
DependencyProperty.RegisterAttached("VerticalOffset", typeof(object), typeof(Camera), new UIPropertyMetadata(null, VerticalOffsetPropertyChanged));
public static object GetVerticalOffset(DependencyObject obj)
{
return (string)obj.GetValue(VerticalOffsetProperty);
}
public static void SetVerticalOffset(DependencyObject obj, object value)
{
obj.SetValue(VerticalOffsetProperty, value);
}
public static void VerticalOffsetPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
Camera cam = o as Camera;
ScrollViewer scroll = cam.Template.FindName("cameraViewer", cam) as ScrollViewer;
double vertical = 0;
if (e.NewValue is double)
{
vertical = (double)e.NewValue;
}
scroll.ScrollToVerticalOffset(vertical);
}
#endregion
}
希望这能让你走上正轨
答案 1 :(得分:0)
如果您喜欢自定义控件,则应创建DependencyProperty。你创建了AttachedProperty,这是其他的东西。
我会告诉你,如何使用附属物:
<ScrollViewer x:Name="ScrollViewer1" Height="100" Width="150"
HorizontalScrollBarVisibility="Auto"
local:ScrollViewerExtension.HorizontalOffset="{Binding Value, ElementName=Slider1}">
<Rectangle Height="80" Width="100" Margin="100,50,0,0" Fill="Red"/>
</ScrollViewer>
<!-- you can databind ScrollViewerExtension.HorizontalOffset to whatever,
Slider is just for demonstration purposes -->
<Slider x:Name="Slider1"
Maximum="{Binding ElementName=ScrollViewer1, Path=ScrollableWidth}" />
和附加的属性定义:
public static class ScrollViewerExtension
{
public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.RegisterAttached("HorizontalOffset", typeof (double), typeof (ScrollViewerExtension),
new PropertyMetadata(HorizontalOffsetChanged));
private static void HorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var scrollViewer = (ScrollViewer) d;
scrollViewer.ScrollToHorizontalOffset((double)e.NewValue);
}
public static void SetHorizontalOffset(DependencyObject element, double value)
{
element.SetValue(HorizontalOffsetProperty, value);
}
public static double GetHorizontalOffset(DependencyObject element)
{
return (double) element.GetValue(HorizontalOffsetProperty);
}
}
如您所见,附加属性应与现有控件一起使用。如果创建新控件,请使用依赖项属性