简体   繁体   English

为 ViewModel 之外的属性提升属性更改

[英]Raising Property Changed for property outside of the ViewModel

Using MvvmCross, fwiw I have a ViewModel with several properties created primarily for ease XAML binding purposes.使用 MvvmCross,fwiw 我有一个 ViewModel,其中包含几个主要为了简化 XAML 绑定目的而创建的属性。 For example:例如:

public int HomeScore
{
   get { return Contest.Team[HomeID].Score; }
}

HomeScore is bound to a TextBlock in the XAML view. HomeScore 绑定到 XAML 视图中的 TextBlock。 Contest is a singleton class that contains a dictionary Team of two teams, HomeID representing one of the Keys. Contest 是一个 singleton class 包含两个团队的字典 Team,HomeID 代表其中一个 Keys。 The value is a class of TeamStats, that contains a property integer Score.该值为 TeamStats 的 class,其中包含一个属性 integer Score。 The current dilemma / challenge is when another method updates the Score, how should that notification get passed on to the ViewModel and subsequently the View to show the updated score in the display.当前的困境/挑战是当另一种方法更新分数时,该通知应该如何传递到 ViewModel 以及随后的视图以在显示器中显示更新的分数。 I've played around with the MvvmCross SetProperty and RaisePropertyChanged at various levels but all to no avail.我在不同级别尝试过 MvvmCross SetProperty 和 RaisePropertyChanged,但都无济于事。

If the Team's "Score" property itself publishes/raises PropertyChanged, you need to listen to it and on any change raise PropertyChanged for "HomeScore".如果团队的“Score”属性本身发布/引发 PropertyChanged,您需要收听它并在任何更改时引发“HomeScore”的 PropertyChanged。

Contest.Team[HomeID].PropertyChanged += PropagateHomeScore;

private void PropagateHomeScore (object sender, PropertyChangedEventArgs args)    { 
   if (e.PropertyName == "Score") {
      RaisePropertyChanged (nameof(HomeScore))
    }
}

By the way, if you discard the convenience wrapper "HomeScore" and put the property path directly in XAML, you don't have to do anything.顺便说一句,如果你放弃便利包装“HomeScore”并将属性路径直接放在 XAML 中,你什么都不用做。

WPF would bind the complete path including the change listeners automagically. WPF 将自动绑定包括更改侦听器在内的完整路径。 Afaik it can handle the dictionary indexer. Afaik 它可以处理字典索引器。

XAML XAML

<TextBlock Text="{Binding Contest.Team[HomeID].Score}" />

(HomeID should likely be replaced by its actual value). (HomeID 应该很可能被其实际值所取代)。

** Update: ** 更新:

Demo for Binding to a dictionary of a static class **绑定到字典的演示 static class **

XAML Window1.xaml XAML 窗口 1.xaml

<Window x:Class="WpfApp1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApp1"
    Title=""
    Width="700"
    Height="220">
    <StackPanel HorizontalAlignment="Center">
        <StackPanel.Resources>
            <Style x:Key="Style1" TargetType="Control">
                <Setter Property="FontSize" Value="20" />
                <Setter Property="FontWeight" Value="Bold" />
                <Setter Property="Padding" Value="20" />
                <Setter Property="VerticalAlignment" Value="Center" />
            </Style>
        </StackPanel.Resources>
        <Label Style="{StaticResource Style1}">Dictionary-Binding + INotifyPropertyChanged Demo</Label>

        <StackPanel HorizontalAlignment="Center"
            Orientation="Horizontal">

            <Button Margin="10"
                Click="ButtonBase_OnClick"
                Content="Increment:"
                Style="{StaticResource Style1}" />
            <TextBox Foreground="Magenta"
                IsReadOnly="True"
                Style="{StaticResource Style1}"
                Text="{Binding Source={x:Static local:Contest.Team}, Path=[1].Score, Mode=OneWay}" />

        </StackPanel>
    </StackPanel>
</Window>

CS: Window1.xaml.cs Code behind + VM CS: Window1.xaml.cs 代码隐藏 + VM

namespace WpfApp1 {

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows;

    public partial class Window1 {
        public Window1() => InitializeComponent();
        private void ButtonBase_OnClick(object sender, RoutedEventArgs e) => Contest.Team[1].Score++;
    }
    public static class Contest {
        public static Dictionary<int, ScoreObject> Team { get; } = new() {
                                 { 1, new ScoreObject { Score = 10 } },
                                 { 2, new ScoreObject { Score = 20 } },
                                 { 3, new ScoreObject { Score = 30 } },
                                 { 4, new ScoreObject { Score = 40 } },
        };
    }
    public class ScoreObject : INotifyPropertyChanged {
        private int _score;
        public int Score {
            get => _score;
            set {
                if (_score != value) {
                    _score = value;
                    OnPropertyChanged(nameof(Score));
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM