【问题标题】:MVVM confusion trying to get INotifyProprerty change to work with XAML updatesMVVM 混淆试图让 INotifyProprerty 更改与 XAML 更新一起使用
【发布时间】:2017-07-30 20:48:34
【问题描述】:

我已经搜索并阅读了大量类似的主题,还观看了一些视频,但我遇到了一些问题,我认为这归结为一些误解。我正在使用 MVVM 和 UWP 开发来学习 70-357 考试。

我的目标:在我的 XAML 页面中按下一个按钮,让它在我的 ViewModel 中更改一个对象的属性,然后让该值反映在我的 XAML 视图中的数据绑定中。

在我的项目中,我有以下内容:

主页 XAML

<StackPanel Name="HPStack" Margin="0,0,10,0">
        <Button Name="HPIncrease" Click="{x:Bind CharacterViewModel.HPIncrease_Click}" Content="+" HorizontalAlignment="Center"/>
        <TextBlock Name="HPTB" Text="{x:Bind CharacterViewModel.myCharacter.CurrentHP}" Margin="0,0,5,0" HorizontalAlignment="Center"/> 
    <Button Name="HPDecrease" Click="{x:Bind CharacterViewModel.HPDecrease_Click}" Content="-" HorizontalAlignment="Center"/>
</StackPanel>

MainPage C#

public CharacterDetailsViewModel CharacterViewModel;

public MainPage()
{
    this.InitializeComponent();
    CharacterViewModel = new CharacterDetailsViewModel();
}

字符视图模型(大部分代码来自我看到的解释here

public class CharacterDetailsViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        //App data
        private Character _myCharacter;
        public Character myCharacter
        {
            set
            {
                _myCharacter = value;
                OnPropertyChanged();
            }
            get { return _myCharacter; }
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        //Constructors
        public CharacterDetailsViewModel()
        {
            _myCharacter = new Character(12, 12, 12, 12, 12, 12);
        }

        //buttons
        public void HPIncrease_Click(object sender, RoutedEventArgs e)
        {
            //TODO probably fix this
            myCharacter.CurrentHP++;
        }

        public void HPDecrease_Click(object sender, RoutedEventArgs e)
        {
            myCharacter.CurrentHP--;
        }

    }

字符模型(去掉很多不相关的属性)

public class Character
{

    public int TotalHP { get; set; } //TODO not public
    public int CurrentHP {get;set;} //TODO check vs total HP and 0

//constructor for creating a new character with provided stats
public Character (int strength, int dexterity, int constitution, int intelligence, int wisdom, int charisma)
    {
        this.TotalHP = 50;
        this.CurrentHP = 45;
    }
}
  • 我的所有属性最初似乎都能正确找到
  • 当我单击按钮更改 CurrentHP 时,我没有看到 XAML 上反映了这一点
  • 我知道存在 prismtemplate 10。我不想使用它们,因为我正在编写此代码以更好地理解这些东西以准备认证。将来我可能会利用它们,但我试图找出在这种情况下我做错了什么。

到目前为止,我的理解是我应该只将 INotfyPropertyChanged 放在 ViewModel 上,它可以处理自定义对象(在本例中为字符)内的任何属性已更改的警报。

我错了吗? 我的 Character 类是否需要 INotifyPropertyChanged 才能正确提醒 XAML 这些更改?

感谢您在此提供的任何意见。

【问题讨论】:

  • 请使用Command 而不是click 事件。
  • 请在 INotifyPropertyChanged 上课。
  • 我看到两件事:是的,您应该更改属性以通知 UI,第二 - 您已将绑定定义为 OneTime - 将其更改为 OneWay 如果您想查看更改。
  • 是的,您需要为CurrentHP 加薪PropertyChanged。或者至少你可以为 myCharacter 属性提高它,视图可以用新值更新它
  • @NikhilAgrawal 你有关于Command和Click之间区别的好资源我可以看看吗?

标签: c# xaml mvvm uwp inotifypropertychanged


【解决方案1】:

阻止您的 UI 更新的两件事:

  • 您的 Character 没有实现 INotifyPropertyChanged,因此不会通知 UI 更改。实现它并在适当的设置器中调用 OnPropertyChanged,否则您将不得不在 myCharacter 上调用 OnPropertyChanged,这应该会刷新整个 Character,但是第一种方法更好,
  • 第二个重要的事情是它也不会起作用,除非你让你绑定 OneWay - x:Bind 是默认的OneTime,所以你应该更正:
<TextBlock Name="HPTB" Text="{x:Bind CharacterViewModel.myCharacter.CurrentHP, Mode="OneWay"}"...

【讨论】:

  • 关于绑定方向的说法根本不正确 - 默认情况下绑定是 TwoWay 并且将绑定设置为 OneWay,虽然它可能是可取的,但与此问题无关。
  • @caesay 看看MSDN - Mode propertyThe default is "OneTime".
  • 你是对的!我想我在考虑常规 WPF 而不是 UWP,只是冲动地说,对不起。
  • @caesay 没问题,我也赶上了许多改变的事情。
  • 听起来像这样+@caesay的回答有助于解释这个问题。 x:Bind 需要更改为 OneWay,并且我的 Character 模型也需要实现 InotifyPropertyChanged。将此标记为答案,稍后我会在回家时尝试进行更改。谢谢!
【解决方案2】:

在您的视图模型中,您已经实现了INotifyPropertyChanged,因此如果您将Character 设置为一个新对象,该事件将被执行并且WPF 将更新。

问题是当Character 的属性发生变化时,不会发送通知事件,WPF 也不知道刷新它的值。

您可以在Character 中实现接口,在视图模型上触发INotifyPropertyChanged,或者将Character 的公共属性改为依赖属性。

【讨论】:

  • 我想这就是我想要的。这么多帖子和视频都在谈论只将 INotifyPropertyChanged 放在 ViewModel 上,知道为什么这似乎被强调得很重吗?我将不得不研究依赖属性;我想我从来没有用过它们。
  • 我无法解释为什么人们会强调一些错误的东西。在您的示例中,由于您要从视图模型本身更新值,因此您当然可以手动触发视图模型上的通知事件(将 Character 指定为更改的内容)。这只是一个简单的事实,如果没有 WPF 无法知道的通知事件:)
  • 我想我只是认为我的 setter 中的代码在说“嘿,这个 myCharacter 属性上的某些东西发生了变化”,这会导致数据绑定再次查看它的所有属性。仅当底层数据类型也知道如何自己执行 INotifyPropertyChange 时才调用 ViewModel 上的更新?
  • @Sambardo:确实是这么说的——但是 setter 什么时候被执行?只有当你 set Character (到一个新对象)时它才会被执行。您正在做的是获取 Character,然后更改其上的一个属性,该属性完全超出了您的视图模型的属性范围。
  • 这很有帮助。我的理解是,如果我完全更改了 myCharacter.CurrentHP,它会以某种方式通过 ViewModel 中的设置器,这听起来是不正确的。我是否可以将 OnPropertyChanged() 移动到按钮本身以提醒它 myCharacter 已更改,或者这不是正确的做事方式?
猜你喜欢
  • 2013-01-18
  • 1970-01-01
  • 2012-09-14
  • 2020-07-01
  • 1970-01-01
  • 2021-06-08
  • 2018-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多