【问题标题】:Bind two properties on target to single source将目标上的两个属性绑定到单个源
【发布时间】:2014-02-22 10:09:50
【问题描述】:

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

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

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

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

创建一个新的矩形类,我称之为 ExtendedRectangle,并在其中创建一个自定义 DependencyProperty,让我可以通过 Point 控制 Grid.RowProperty 和 Grid.ColumnProperty。

问题是调试代码并在我的 setter 和 getter 上设置断点,似乎在使用 setValue() 方法执行期间没有达到断点,但是当我显式修改其值时它们被调用。此外,我在运行时更改了 Agents 矩形的位置,我看到值正在更新,但我的 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);
        }
    }

【问题讨论】:

    标签: c# wpf data-binding


    【解决方案1】:

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

    但是,您的ExtendedRectangle 类根本不需要。您可以轻松地将常规 Rectangle 上的 Grid.ColumnGrid.Row 属性绑定到 Agent 类中的点属性。此外,为了简化您的绑定,您的 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);
    

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

    接下来,如果您的绑定应该在运行时更新,您必须在您的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 值的结构。也许写你自己的。

    【讨论】:

    • 我放弃了自定义 DependencyProperty 的想法,像你写的那样实现了绑定,它现在可以工作了! :D 但是我仍然对 CLR 包装器方法有疑问,你说它不应该调用其他任何东西 Get/SetValue()...所以如果我想在我的实现中从 Getter 返回一个 Point,我怎么能这样做是因为我需要这两个值来创建一个?
    • 请参阅 MSDN 上 Checklist for Defining a Dependency PropertyXAML Loading and Dependency Properties 中的 实现“包装器” 部分,了解为什么 CLR 包装器方法不应调用 GetValue 和设定值。转换为另一种属性类型将由 binding converter 完成。
    猜你喜欢
    • 2012-10-26
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    相关资源
    最近更新 更多