首页 > 解决方案 > 我有两个 WPF 控件,但是当我刷新它们的数据绑定时,只有一个在刷新

问题描述

我有一个BindableGrid在 WPF 中创建的控件,并在我的页面上实例化了其中的两个:

<Viewbox Name="galaxyViewbox" Width="400" Height="400" DataContext="{x:Static models:Galaxy.Current}">
    <local:BindableGrid x:Name="galaxyMap" ArraySource="{Binding StarSystemArray}" CellSize="16" BackgroundImage="/Images/Starfield.png">
        <local:BindableGrid.ItemTemplate>
            <DataTemplate>
                <local:TileView ImagePaths="{Binding ImagePaths}"/>
            </DataTemplate>
        </local:BindableGrid.ItemTemplate>
    </local:BindableGrid>
</Viewbox>

<Viewbox Name="starSystemViewbox" Stretch="Uniform" Grid.RowSpan="2" Grid.Column="1" DataContext="{x:Static models:StarSystem.Current}">
    <Grid>
        <local:BindableGrid x:Name="starSystemMap" ArraySource="{Binding SpaceObjectArray}" CellSize="64" BackgroundImage="/Images/Starfield.png">
            <local:BindableGrid.ItemTemplate>
                <DataTemplate>
                    <local:TileView ImagePaths="{Binding ImagePaths}"/>
                </DataTemplate>
            </local:BindableGrid.ItemTemplate>
        </local:BindableGrid>
        ...
    </Grid>
</Viewbox>

他们俩都在显示适当的图像;但是当我的游戏中玩家飞船当前占用的星系统发生变化时,只有starSystemMap控件更新;GalaxyMap 控件也没有更新(它应该在当前占用的系统上显示一个船图标)。我看不出这些控件的绑定方式有什么不同。每次玩家船移动以强制他们刷新时,我都会调用此代码:

galaxyMap.GetBindingExpression(BindableGrid.ArraySourceProperty).UpdateTarget();
starSystemMap.GetBindingExpression(BindableGrid.ArraySourceProperty).UpdateTarget();

我知道还有其他代码与之交互;让我知道您是否需要查看其他任何内容来解决这个问题!谢谢!

编辑:分享更多细节,首先是BindableGrid.ArraySource:

    /// <summary>
    /// The array to bind to. Should be a 1D or 2D array.
    /// </summary>
    public Array ArraySource
    {
        get { return (Array)GetValue(ArraySourceProperty); }
        set { SetValue(ArraySourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ArraySource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ArraySourceProperty =
        DependencyProperty.Register(nameof(ArraySource), typeof(Array), typeof(BindableGrid), new PropertyMetadata(null));

和 BindableGrid.OnPropertyChanged:

protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);

        if (e.Property == ArraySourceProperty || e.Property == ItemTemplateProperty || e.Property == CellSizeProperty || e.Property == BackgroundImageProperty)
        {
            if (ArraySource != null)
            {
                ColumnDefinitions.Clear();
                RowDefinitions.Clear();
                int width = ArraySource.GetLength(0);
                int height = ArraySource.Rank == 1 ? 1 : ArraySource.GetLength(1);
                for (var x = 0; x < width; x++)
                    ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(CellSize) });
                for (var y = 0; y < height; y++)
                    RowDefinitions.Add(new RowDefinition { Height = new GridLength(CellSize) });
                if (ItemTemplate != null)
                {
                    for (var x = 0; x < width; x++)
                    {
                        for (var y = 0; y < height; y++)
                        {
                            var item = ArraySource.Rank == 1 ? ArraySource.GetValue(x) : ArraySource.GetValue(x, y);
                            var box = Children.Cast<UIElement>().Where(b => (int)b.GetValue(RowProperty) == y && (int)b.GetValue(ColumnProperty) == x && (int)b.GetValue(RowSpanProperty) == 1 && (int)b.GetValue(ColumnSpanProperty) == 1).SingleOrDefault();
                            if (box == null)
                            {
                                box = (UIElement)ItemTemplate.LoadContent();
                                box.SetValue(ColumnProperty, x);
                                box.SetValue(RowProperty, y);
                                Children.Add(box);
                            }
                            if (item == Wormholes.Models.StarSystem.Current)
                            {

                            }
                            box.SetValue(DataContextProperty, item);
                        }
                    }
                }
            }
            if (bg != null)
                bg.Source = BackgroundImage;
            else
                bg = new Image { Source = BackgroundImage };
            if (ColumnDefinitions.Count > 0 && RowDefinitions.Count > 0)
            {
                bg.SetValue(ColumnSpanProperty, ColumnDefinitions.Count);
                bg.SetValue(RowSpanProperty, RowDefinitions.Count);
                if (!Children.Contains(bg))
                    Children.Add(bg);
            }
        }
    }
}

编辑:这是我的 ImagePaths 属性,它没有被反弹以显示每个恒星系统的最新图像:

public ObservableCollection<string> ImagePaths { get; set; } = new ObservableCollection<string>();

public void RefreshImagePaths()
{
    ImagePaths.Clear();
    ImagePaths.Add("Star");
    if (Current == this)
    {
        foreach (var ip in PlayerShip.Instance.ImagePaths)
            ImagePaths.Add(ip);
    }
}

RefreshImagePaths 在您移出的星系统和您更改星系统时移入的星系统上调用。

编辑:真正有趣的是我box.SetValue(DataContextProperty, item);在绑定 BindableGrid 时调用,但 UI 并未针对银河地图更新...

编辑:这是我的 TileView.xaml.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Wormholes.Views
{
    /// <summary>
    /// Interaction logic for TileView.xaml
    /// </summary>
    public partial class TileView : UserControl
    {
        public TileView()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Paths to images to display, from back to front Z-index.
        /// </summary>
        public ObservableCollection<string> ImagePaths
        {
            get { return (ObservableCollection<string>)GetValue(ImagePathsProperty); }
            set { SetValue(ImagePathsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImagePaths.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImagePathsProperty =
            DependencyProperty.Register(nameof(ImagePaths), typeof(ObservableCollection<string>), typeof(TileView), new PropertyMetadata(null));

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);

            if (e.Property == ImagePathsProperty)
            {
                grid.Children.Clear();
                if (ImagePaths != null)
                {
                    foreach (var ip in ImagePaths)
                    {
                        try
                        {
                            var img = new Image { Source = new BitmapImage(new Uri(System.IO.Path.GetFullPath(System.IO.Path.Combine("Images", ip + ".png")), UriKind.RelativeOrAbsolute)), Width = Width, Height = Height };
                            grid.Children.Add(img);
                        }
                        catch (FileNotFoundException ex)
                        {
                            Console.Error.WriteLine($"Could not find image: {ip}");
                        }
                        catch (DirectoryNotFoundException ex)
                        {
                            Console.Error.WriteLine($"Could not find image: {ip}");
                        }
                    }
                }
            }
        }
    }
}

标签: c#wpf

解决方案


OnPropertyChangedmy的方法TileView从未被调用,因为TileView's DataContextImagePaths从未真正改变过;只有里面的项目ImagePaths改变了。因此我不得不强制刷新BindableGrid.OnPropertyChanged

box.DataContext = null;
box.DataContext = item;

我确信有更好的方法可以做到这一点,但现在,它有效!


推荐阅读