1

我正在尝试用 WPF 和 C# 中的 DataBinding 做一件小事,但我无法理解 DataBinding 的任何教程。我的问题是,我在 C# 中有一个字符类,它有 X 和 Y 坐标与 get并设置功能。然后我在窗口的画布中有一个图像,现在我试图将角色类的坐标绑定到图像。(只有一个图像,并且只会创建一个角色类的实例,虽然不是在开始时)。希望任何人都可以解释一下,以便我完全理解它:/

编辑:

这是 XAML:

<Window x:Class="ProjectChar.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="800" Width="1000" Background="Gray">
<Viewbox StretchDirection="Both" Stretch="Uniform">
    <Grid>
        <Canvas Name="Canv" Background="White" Visibility="Hidden" MaxHeight="750" MaxWidth="1000">
            <Canvas.LayoutTransform>
                <ScaleTransform ScaleY="-1"/>
            </Canvas.LayoutTransform>
            <Image Name="CharImage"  Source="CharBild.png" Canvas.Left="{Binding iXCoordinate}" Canvas.Top="{Binding iYCoordinate}"/>
        </Canvas>
    </Grid>
</Viewbox>

这是 C# 部分:

namespace ProjectChar
{
    public class Char : MainWindow
    {
        public int iXCoordinate { get; set; }
        public int iYCoordinate { get; set; }
    }
}

所以我需要以某种方式将它们绑定在一起,但我不知道如何。我知道我必须创建一个 DataContext 并且我需要将 UpdateSource 设置为 PropertyChanged 并且我需要一个用于 Property Changed 的​​ EventHandler ,但是我不知道该怎么做,互联网上的教程都是说不同的事情:/

4

1 回答 1

3

要将Image的 X 和 Y 坐标绑定到您的属性,请执行以下操作:

  1. 从 中删除Char的继承MainWindow
  2. MainWindow's设置DataContextChar.
  3. Visibility="Hidden"_Canvas

例子:

public class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new Char { iXCoordinate = 20, iYCoordinate = 50 };
    }
}

确保您确实将iXCoordinateandiYCoordinate属性设置为某些东西。如果不是,它们将是 的默认值int,即 0。例如,图像将显示在左上角。

要让视图 (UI) 知道绑定值何时发生更改,请在每次设置属性时实现INotifyPropertyChanged并引发事件:PropertyChanged

public class Char : INotifyPropertyChanged
{
    private int _iXCoordinate;

    public int iXCoordinate
    {
        get { return _iXCoordinate; }
        set
        {
            _iXCoordinate = value;
            OnPropertyChanged("iXCoordinate");
        }
    }

    private int _iYCoordinate;

    public int iYCoordinate
    {
        get { return _iYCoordinate; }
        set
        {
            _iYCoordinate = value;
            OnPropertyChanged("iYCoordinate");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

这是最简单的实现方式INotifyPropertyChanged。但是,我建议创建一个实现接口的基类,并让您的 ViewModels 从中继承。尝试这样的事情:

public class PropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
    {
        var handler = PropertyChanged;
        var propertyName = GetPropertyName(propertyExpression);
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    private static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
    {
        var memberExpression = propertyExpression.Body as MemberExpression;
        if (memberExpression == null)
        {
            var unaryExpression = propertyExpression.Body as UnaryExpression;
            if (unaryExpression == null) 
                throw new ArgumentException("Expression must be a MemberExpression.", "propertyExpression");

            memberExpression = unaryExpression.Operand as MemberExpression;
        }

        if (memberExpression == null) 
            throw new ArgumentException("Expression must be a MemberExpression.", "propertyExpression");

        var propertyInfo = memberExpression.Member as PropertyInfo;
        if (propertyInfo == null) 
            throw new ArgumentException("Expression must be a Property.", "propertyExpression");

        return propertyInfo.Name;
    }
}

PropertyChangedBase还有一个额外的好处,即您必须PropertyChanged使用 lambda 表达式而不是使用"magic strings"来引发事件,这很容易出现拼写错误并且不利于重构:

    public int iYCoordinate
    {
        get { return _iYCoordinate; }
        set
        {
            _iYCoordinate = value;
            OnPropertyChanged(() => iYCoordinate);
        }
    }

但是,您真正的问题是ViewBox包装Grid.

AViewBox测量它的孩子的大小Infinity,然后按他们的大小排列它们DesiredSize。这意味着它的孩子可以是他们想要的任何大小。两者GridCanvas没有他们想要的尺寸,他们依靠父母给他们一个尺寸。

要解决您的问题,请指定Width其中HeightGridCanvas内部的和。

顺便说一句:你知道的

<Canvas.LayoutTransform>
  <ScaleTransform ScaleY="-1"/>
</Canvas.LayoutTransform>

会翻转你的卡瓦斯,对吧?

于 2012-11-20T20:06:41.793 回答