无法使用UpdateSourceTrigger = PropertyChanged更新WPF

时间:2017-11-17 18:20:07

标签: c# .net wpf xaml

首先(完全披露),我是C#的相对初学者,所以这可能是一个明显的哎呀。我已经在stackoverflow上回顾了几十个类似的问题和示例,我仍然无法将我的发现者放在我做错的事情上。我开始使用VS 2017 WPFapp项目。更改了OnStartup,因此我可以手动加载我的窗口。创建一个带有计时器的类,该计时器递增一个值,然后使用INotifyPropertyChanged更新MainWindow上的TextBox。

WPF窗口加载正常。 TextBlock以值5开头,因此绑定至少指向我的类和值。您将在输出中注意该值正在使用timer事件进行更新,并且NotifyPropertyChanged正在触发,但TextBlock永远不会更改。

我唯一的想法是TextBlock链接到我的UpdateWPF类的错误实例,但我不知道它是怎么回事。

提前感谢您的帮助!

这是我的代码......

MainWindow.xaml:(真的只是丢弃了一个文本块并设置了绑定)

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <Grid>
        <TextBlock HorizontalAlignment="Left" Height="50" Margin="139,123,0,0" TextWrapping="Wrap" Text="{Binding Path=GetValue,Mode=OneTime,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="215"/>
    </Grid>
</Window>

MainWindow.xaml.cs (根本没有更改此代码)

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

App.xaml (刚刚注释掉了StartupUri)

<Application x:Class="WpfApp1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApp1">
            <!--StartupUri="MainWindow.xaml"-->
    <Application.Resources>

    </Application.Resources>
</Application>

App.xaml.cs (肉和土豆)

namespace WpfApp1
{
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {


            base.OnStartup(e);
            UpdateWPF uWPF = new UpdateWPF();
            MainWindow w = new MainWindow();
            w.DataContext = uWPF;
            w.Show();
        }

        public class UpdateWPF : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged(String propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                Console.WriteLine("NotifyPropertyChanged Fired.");
            }

            private int value = 5;
            public UpdateWPF()
            {
                Timer aTimer = new System.Timers.Timer();
                aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
                aTimer.Interval = 1000;
                aTimer.Enabled = true;
            }
            private void OnTimedEvent(object source, ElapsedEventArgs e)
            {
                value++;
                Console.WriteLine("Timer Event Fired. New Value is " + value.ToString());
                NotifyPropertyChanged(nameof(GetValue));
            }
            public string GetValue => (value.ToString());
        }
    }
}

和输出

Timer Event Fired. New Value is 6 
NotifyPropertyChanged Fired. 
Timer Event Fired. New Value is 7 
NotifyPropertyChanged Fired. 
Timer Event Fired. New Value is 8 
NotifyPropertyChanged Fired. 
Timer Event Fired. New Value is 9 
NotifyPropertyChanged Fired. 
Timer Event Fired. New Value is 10 
NotifyPropertyChanged Fired. 
Timer Event Fired. New Value is 11 
NotifyPropertyChanged Fired.

2 个答案:

答案 0 :(得分:0)

正如上面的评论中所说,您必须正确设置UpdateSourceTrigger。我也不建议您实施属性的方式。他们应该是这样的:

private int _value;

public int Value
{
    get => _value;
    set
    {
        _value = value;
        OnPropertyChanged(nameof(Value));
    }
}

现在您可以说Value = 0;而不是手动提升PropertyChanged事件。

如果您将NotifyPropertyChanged方法更改为:

private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgw(propertyName));
            Console.WriteLine("NotifyPropertyChanged Fired.");
}

您不必将属性名称传递给NotifyPropertyChanged。由于CallerMemberNameAttribute

,运行时将自动执行此操作

问候

洛里斯

修改

我的属性示例只是一个属性的示例,而不是您的。但你只需改变类型就可以了。

这应该适合你:

public class UpdateWPF : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            Console.WriteLine("NotifyPropertyChanged Fired.");
        }

        private int _value = 5;

        public UpdateWPF()
        {
            Timer aTimer = new System.Timers.Timer();
            aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            aTimer.Interval = 1000;
            aTimer.Enabled = true;
        }
        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            var i = Convert.ToInt32(value);
            Value = ++i;
        }
        public string Value
        {
            get => _value;
            set
            {
                _value = value;
                NotifyPropertyChanged();
            }
        }
    }

答案 1 :(得分:0)

ASh发现了我的问题,但他发布了评论,所以我会回答这个问题。由于我在此过程中解决了其他一些问题,因此我将其全部发布在此处。

真正的问题出在我的MainWindow.xaml

Text="{Binding Path=GetValue,Mode=OneTime,UpdateSourceTrigger=PropertyChanged}"

应该是

Text="{Binding Path=GetValue,Mode=OneWay}"

稍后将成为

Text="{Binding Path=Value,Mode=OneWay}"

正如ASh所指出的,在这种情况下,UpdateSourceTrigger完全没有意义。

Loris156指出了其他一些问题。一些建议是错误的,但我偶然发现了好处并且来到了这一点。

命名惯例

我来自java,一切都是GetThis或SetThis,这个是变量。
MS建议Value(){get; set;},其中 value 是变量。 loris156更喜欢 _value ,我看到很多人在做。因为它恰好发生了#34;价值&#34;是一个非常糟糕的例子,因为在auto属性setter中使用。尽管如此,由于我使用他们的编译器,我坚持使用MS的方式。

所以我的getter / setter变成了#34; Value&#34;。

我还要指出Lori156使用了int返回,但这对我正在使用的文本框没有用。

我之前无法让[CallerMemberName]正常工作。这也与我的getter / setter有关。通过排除setter,我破坏了自动属性功能。见understanding private setters

正如我之前提到的,int getter不能使用文本框,因此我选择将字符串转换回setter中的int。这无关紧要,因为我还是不会使用它。 以下是App.xaml.cs的代码更改

private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            Console.WriteLine("NotifyPropertyChanged Fired.");
        }

...

public string Value {
            get => value.ToString();
            private set => this.value = Int32.Parse(value);
        }

如果有人有这些建议,我愿意接受进一步的建议。