【问题标题】:UWP XAML Databinding working on one text box, but not anotherUWP XAML 数据绑定在一个文本框上工作,但不是另一个
【发布时间】:2018-01-11 18:16:29
【问题描述】:

我遇到了一个特殊的问题,将两个文本框数据绑定到同一个对象可以正常工作,但是在我通过 XML 反序列化将数据加载回我的程序后,其中一个文本框的绑定失败。

我使用 splitview 构建一个小汉堡导航菜单并将我的页面加载到框架中

这是我的 MainPage.xaml 中相关的 XAML

<TextBlock Name="PlayerGoldTextBlock" 
                       RelativePanel.RightOf="PlayerNameTextBlock" 
                       RelativePanel.AlignVerticalCenterWithPanel="True" 
                       Foreground="Gold" 
                       FontSize="28" 
                       Text="{x:Bind myGame.Game.Player.Gold, Mode=OneWay}" />    
<TextBlock Name="RemainingTurnsTextBlock" 
                       RelativePanel.RightOf="PlayerGoldTextBlock" 
                       RelativePanel.AlignVerticalCenterWithPanel="True" 
                       Foreground="Red"  
                       Text="{x:Bind myGame.Game.RemainingTurns, Mode=OneWay}" />
<SplitView.Content>
       <Frame Name="MyFrame"></Frame>
</SplitView.Content>

在我已经加载到框架中的页面中:

<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
    <TextBlock Text="Gold:" HorizontalAlignment="Left" FontSize="16" Margin="0,0,10,0"/>
    <TextBlock Text="{x:Bind myGame.Game.Player.Gold, Mode=OneWay}" HorizontalAlignment="Left" FontSize="16" Margin="0,0,10,0"/>
</StackPanel>

在 MainPage 中:PlayerGoldTextBlock 在我加载后无法正确绑定,但 RemainingTurnsTextBlock 工作正常

在我的框架中:x:Bind myGame.Game.Player.Gold 在我加载后似乎重新绑定就好了。

另一件可能相关的事情是,在加载时我看到 RemainingTurnsTextBlock 立即更新,但框架中的(工作)播放器黄金直到我导航到不同的框架然后返回

这是我的反序列化代码,以防万一:

async public void LoadGame()
{
    var filename = "testsave.xml";
    var serializer = new XmlSerializer(typeof(GameModel));
    StorageFolder folder = ApplicationData.Current.LocalFolder;
    StorageFile file = await folder.GetFileAsync(filename).AsTask().ConfigureAwait(false);
    Stream stream = await file.OpenStreamForReadAsync().ConfigureAwait(false);

    GameModel myGame;
    using (stream)
    {
        myGame = (GameModel)serializer.Deserialize(stream);
        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 
        {
            this.Player = myGame.Player;
            this.Locations = myGame.Locations;
            this.RemainingTurns = myGame.RemainingTurns;
        });
    }
}

这是我的 GameModel 中的一些属性

public Player Player { get; set; }
public int MaxTurns { get; set; }
private int remainingTurns;
public int RemainingTurns
{
    get { return remainingTurns; }
    set { SetProperty(remainingTurns, value, () => remainingTurns = value);}
}

这是播放器中的黄金属性

private int gold;
public int Gold
{
    get { return gold; }
    set {SetProperty(gold, value, () => gold = value);}
}

这里是设置属性

protected bool SetProperty<T>(T currentValue, T newValue, Action DoSet,
    [CallerMemberName] String property = null)
{
    if (EqualityComparer<T>.Default.Equals(currentValue, newValue)) return false;
    DoSet?.Invoke();
    RaisePropertyChanged(property);
    return true;
}

根据 XY 问题评论进行编辑以澄清问题陈述:

  • 我有绑定到 Game.Player.Gold 的东西
  • 在启动时它们运行良好
  • 在进行 XML 反序列化并加载保存的状态后,当我离开并返回时,一些绑定工作,但有些完全死了
  • 当我更改播放器实例或其他东西时,绑定似乎不喜欢,因为它无法深入了解黄金属性的位置。对我来说很奇怪,框架中的一个文本框可以在我导航后重新绑定,但主窗口中的一个文本框不能
  • 我找到了解决此问题的方法,除了 Game.Player.Gold 之外,直接在 Game.Player 上使用设置器,但我发现其他属性也出现了一些类似的问题。
  • 我是否对这些事物如何看待彼此有一些误解?

【问题讨论】:

  • 你是如何声明你的属性的?你在用 Fody 吗?
  • 在我相信的相关属性中进行了编辑。我不确定 Fody 是什么,所以可能不会使用它。如果它是一个框架,我只是自己构建了这一切来学习 UWP 的东西,而现在我正在用它来玩 XML 序列化之类的东西。
  • 你是如何声明 SetProperty 的?
  • 看起来我编辑的代码被编辑回来了,我稍后再添加。代码的哪一部分显示为不可读?这一切都显示在我的浏览器中带有格式和语法的代码块中。
  • 我想是的:你压平了一些标签,我会在粘贴之前压平东西。干杯。

标签: c# xaml data-binding uwp


【解决方案1】:

您没有实时更新myGame.Game.Player.Gold,因此当页面重新加载框架时,它将从 Player 类中获取详细信息,但缺少在更改时立即更新的详细信息,如 RemainingTurns 所做的那样。框架和主窗口之间的访问器可能存在问题。

await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 
{
    this.Player = myGame.Player;
    this.Locations = myGame.Locations;
    this.RemainingTurns = myGame.RemainingTurns;
    // You need to get the value for Player.Gold
});

【讨论】:

  • 我不确定我是否遵循。当我稍后(无论多少次)再次更改黄金值时,它会在框架中更新,但不会在主页中更新。如果我必须为此重新加载主页,那我为什么不保留剩余的转数呢?您是指我在上面的代码段中重置播放器的那一刻,还是这就是绑定在主页上完全消失的原因?
  • 您的意思是,如果不重新加载主页或向该属性添加 set 方法,它就无法看到我加载到播放器属性中的新播放器实例?我印象深刻的是,由于它绑定到游戏模型中的属性,它应该能够看到。
  • 这应该在上面进行编辑,它是一个带有 setter 的 int,用于调用 SetProperty 并引发和事件以进行数据绑定。通过将 SetProperty 添加到 GameModel 中的玩家设置器,它似乎已经修复了一些问题,但我仍然不确定我是否理解为什么绑定首先会死掉。这并没有解决另一个属性的问题,尽管它是一个 ObservableCollection。
  • 不,我已经有一个 Player.Gold 的设置器,在上面的帖子中,以及为什么我的绑定完全有效。我为游戏的 Player 属性添加了它。这专门解决了 Gold 的问题,但没有解决其他一些属性,例如 ObservableCollection
  • 我做了,但我仍然不确定为什么需要添加,这让我相信问题更深层次,我添加的只是具有特定副作用的创可贴。
【解决方案2】:

我通过向我的游戏中的 Player 属性添加一个 Setter 解决了这个问题

public Player Player
{
    get { return player; }
    set { SetProperty(player, value, () => player = value); }
}

这似乎会触发任何订阅玩家属性的事件,即玩家已更改。

但是,它并没有解决我在加载后看到的不同播放器属性的所有数据绑定问题。例如,在导航帧之前,ObservableCollection 属性似乎仍然无法正确绑定。

当我开始游戏时它运行良好,但在我从 XML 加载数据后,即使添加了此修复程序,它仍然需要导航才能正确填充。

我不确定这是否是正确的修复,我还有第二个问题,或者此修复是否只是解决部分问题的奇怪创可贴。这可能是对我没有得到的数据绑定方面或反序列化方面的误解。

【讨论】:

  • 我认为你在这个问题上不清楚。没关系。我已经重读了几次我的帖子,正如我在您的其他帖子中提到的那样,我不确定您在理解哪些部分有困难,所以我无法进一步澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-03
  • 2012-01-07
相关资源
最近更新 更多