相机逻辑WPF(绑定属性)

时间:2015-12-10 16:25:36

标签: c# wpf xaml camera

我正在尝试使用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);
        }
    }
}

2 个答案:

答案 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);
    }
}

如您所见,附加属性应与现有控件一起使用。如果创建新控件,请使用依赖项属性