将目标上的两个属性绑定到单个源

时间:2014-02-22 10:09:51

标签: c# wpf data-binding

我正在开发一个带有WPF和C#的迷宫,我将一个代理放在迷宫内的一个随机位置,GUI显示了使用搜索算法找到退出的过程。

我首先在行和列上划分网格,然后在每个网格/行对上添加一个矩形,最后我在代表我的代理的网格中添加一个额外的矩形。

我想将Grid中代理Rectangle的位置绑定到一个Agent类属性,该属性用Point类表示它的位置。

由于我对这些技术还很陌生,所以我在网上看了一下当前的解决方案:

创建一个新的矩形类,我调用ExtendedRectangle并在其中创建一个自定义的DependencyProperty,它通过Point控制Grid.RowProperty和Grid.ColumnProperty。

问题是在我的setter和getter上调试代码和设置断点,似乎在使用setValue()方法执行期间没有达到断点,但是当我明确地修改它的值时它们被调用。此外,我在运行时更改了代理矩形的位置,我看到值正在更新,但我的GUI不是。

我想对这个或更好的方法有所启发。感谢。

这是我在MainWindow.xaml.cs上进行绑定的方法:

    public partial class MainWindow : Window
    {
        Maze maze = new Maze(15, 15);
        TimerCallback callback; //
        Timer stateTimer; //
        public MainWindow()
        {
            InitializeComponent();
            DataContext = maze;
            DrawMap(15, 15);
            callback = new TimerCallback(Update); //
            stateTimer = new Timer(callback, null, 2000, 2000); //
        }

        public void DrawMap(int ancho, int alto)
        {
            /********ADD COLUMNS, ROWS AND RECTANGLES CODE WAS HERE*************/
            // commented code are my tests

            ExtendedRectangle agent = new ExtendedRectangle();
            agent.BaseRectangle.Fill = new SolidColorBrush(Colors.LightGreen);
            //agent.GridPosition = new Point(5, 5);
            //Console.WriteLine(agent.GridPosition.ToString());
            //Console.WriteLine(maze.GetAgent().Position.ToString());
            agent.SetValue(ExtendedRectangle.GridPositionProperty, maze.GetAgent().Position);
            //Console.WriteLine(agent.GridPosition.ToString());
            Binding bind = new Binding("Position") { Source = maze.GetAgent() };
            bind.Mode = BindingMode.OneWay;
            //bind.Converter = new AgentToGridPosition();
            agent.SetBinding(ExtendedRectangle.GridPositionProperty, bind);
            Mapa.Children.Add(agent.BaseRectangle);
        }

        public void Update(Object stateInfo) //
        {
            Random r = new Random();
            int x = r.Next(0, 14);
            int y = r.Next(0, 14);
            Point p = new Point(x, y);

            maze.GetAgent().Position = p;
            Console.WriteLine("UPDATED POSITION:" + maze.GetAgent().Position.ToString());
        }
    }

这是我的ExtendedRectangle类:

    class ExtendedRectangle
    {
        private Rectangle baseRectangle;
        private Point propertyType;

        public ExtendedRectangle()
        {
            baseRectangle = new Rectangle();
            propertyType = new Point();
        }

        public Rectangle BaseRectangle
        {
            get
            {
                return baseRectangle;
            }
        }

        public static readonly DependencyProperty GridPositionProperty = DependencyProperty.Register(
    "GridPosition", typeof(Point), typeof(ExtendedRectangle));

        public Point GridPosition 
        {
            get
            {
                propertyType.X = Convert.ToDouble(baseRectangle.GetValue(Grid.ColumnProperty));
                propertyType.Y = Convert.ToDouble(baseRectangle.GetValue(Grid.RowProperty));
                return propertyType;
            }
            set
            {
                propertyType = value;
                baseRectangle.SetValue(Grid.ColumnProperty, (int)propertyType.X);
                baseRectangle.SetValue(Grid.RowProperty, (int)propertyType.Y);
            }
        }

        public void SetValue(DependencyProperty dp, object value)
        {
            baseRectangle.SetValue(dp, value);
        }

        public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding)
        {
            return baseRectangle.SetBinding(dp, binding);
        }
    }

1 个答案:

答案 0 :(得分:0)

首先,您的GridPosition依赖项属性声明是错误的。 CLR包装器方法必须调用GetValueSetValue,并且不应调用其他任何内容。有关所有详细信息,请参阅MSDN上的Custom Dependency Properties文章。

然而,您的ExtendedRectangle课程根本没有必要。您可以轻松地将常规Rectangle上的Grid.ColumnGrid.Row属性绑定到Agent类中的point属性。此外,为了简化绑定,您的Maze类应该具有Agent属性而不是GetAgent方法。

在XAML中它看起来像这样:

<Grid x:Name="grid">
    ...
    <Rectangle Grid.Column="{Binding Agent.Position.X}"
               Grid.Row="{Binding Agent.Position.Y}"
               Fill="LightGreen"/>
</Grid>

在这样的代码中:

var rectangle = new Rectangle { Fill = Brushes.LightGreen };
rectangle.SetBinding(Grid.ColumnProperty, new Binding("Agent.Position.X"));
rectangle.SetBinding(Grid.RowProperty, new Binding("Agent.Position.Y"));
grid.Children.Add(rectangle);

请注意,通过类Agent中的Maze属性,您无需显式设置绑定源,因为Maze实例已分配给MainWindow的DataContext 1}}。

接下来就是如果你的绑定应该在运行时更新,你必须在Agent类中实现属性更改通知机制。一种方法是实现INotifyPropertyChanged接口,如下所示:

class Agent : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private Point position;
    public Point Position
    {
        get { return position; }
        set
        {
            position = value;
            RaisePropertyChanged("Position");
        }
    }

    protected void RaisePropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

最后,我建议不要将Point用作Agent.Position属性的类型,因为其XY值的类型为double(你已经意识到这一点)。更好地使用具有整数XY值的结构。也许自己写一个。