首页 > 解决方案 > 如何让我的 TextBlock 使用 DataBinding 更新文本

问题描述

所以我似乎陷入了一个循环(没有双关语)。我创建了由 Button 控件和 TextBlock 控件组成的视图。我已将我的按钮绑定到一个命令,该命令从我的模型中调用一个方法。

XAML

<Grid>
    <TextBlock Text="{Binding CounterValue}" Width=" 100" Height="20"></TextBlock>
    <Button Command="{Binding startCommand}" Content="Button" HorizontalAlignment="Left" Margin="472,230,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>

这里是 StartCommand 你可以忽略它,这里没有什么特别的

class StartCommand : ICommand
    {
        private Action _startCommand;
        public StartCommand(Action StartCommand)
        {
            _startCommand = StartCommand;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _startCommand?.Invoke();
        }

        public event EventHandler CanExecuteChanged;
    }

然后我们有一个单独的cs文件的模型。

class CounterModel
    {
        static DispatcherTimer calcTimer = new DispatcherTimer();

        public StartCommand startCommand { get; } = new StartCommand(Start);

        public CounterModel()
        {
            CounterValue = 10;
        }
        private static int _counterValue;
        public static int CounterValue
        {
            get { return _counterValue; }
            set
            {
                _counterValue = value;
            }
        }

        public static void Start()
        {
            //Start some stuff..
            Calculate();
        }

        public static void Calculate()
        {
            calcTimer.Tick += CalcTimer_Tick;
            calcTimer.Interval = TimeSpan.FromSeconds(2);
            calcTimer.Start();
        }

        private static void CalcTimer_Tick(object sender, EventArgs e)
        {
            PerformanceCounter cpuCounter = new PerformanceCounter
                ("Process", "% Processor Time", "Firefox", true);
            CounterValue = (int)cpuCounter.NextValue();
        }
    }

我现在的问题是,当我单击开始按钮时,它什么也没做。或者它是,但我的文本属性没有相应地更新,该值与计时器滴答事件分配给它的新值不对应。我尝试实现接口INotifyPropertyChanged,但我不能这样做。

private static int _counterValue;
public static int CounterValue
{
    get { return _counterValue; }
    set
    {
        _counterValue = value;
        OnPropertyChanged("startCommand");
    }
}

因为OnPropertyChanged那时需要是静态的,这会再次导致我陷入一个全新的兔子整体,我不应该一开始就陷入困境。

而且我需要我的属性是静态的,所以我可以在 Tick 事件中使用它们,该事件是从我的内部调用的计算方法调用的Start()

开始需要是静态的,因为我是从许多其他课程中调用它的。无论哪种方式..

如何处理我的属性是静态的并使用 INotifyPropertyChanged oooor .. 如何在没有的情况下更新 TextBlock 文本值INotifyPropertyChanged

不删除 Start() 中的静态修饰符

是的,我确实设置了 DataContext

public MainWindow()
        {
            InitializeComponent();
            DataContext = new CounterModel();
        }

标签: c#.netmvvmdata-bindingviewmodel

解决方案


我在这里了解您的情况。但是您的 Start() 的可访问性不是更多的设计问题吗?您可以通过实现单例模式以在每次调用时从 start 方法获取值来实现两全其美,而不是使 Start() 成为静态的。你可以看到下面的例子:

 public class CounterModel : INotifyPropertyChanged
{
    private static CounterModel _instance = new CounterModel();

    public static CounterModel Instance { get { return _instance; } }

    private CounterModel()
    {
        CounterValue = 10;
        startCommand = new StartCommand(Start);
    }
    static DispatcherTimer calcTimer = new DispatcherTimer();

    public StartCommand startCommand { get; }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }


    private int _counterValue;
    public int CounterValue
    {
        get
        {
            return _counterValue;
        }
        set
        {
            _counterValue = value;
            NotifyPropertyChanged();
        }
    }
    public void Start()
    {
        //Start some stuff..
        Calculate();
    }
    public void Calculate()
    {
        calcTimer.Tick += CalcTimer_Tick;
        calcTimer.Interval = TimeSpan.FromSeconds(2);
        calcTimer.Start();
    }

    private void CalcTimer_Tick(object sender, EventArgs e)
    {
        PerformanceCounter cpuCounter = new PerformanceCounter
            ("Process", "% Processor Time", "Explorer", true);
        CounterValue = (int)cpuCounter.NextValue();
    }
}

一旦单例模式到位,所有必需的方法都不必是静态的,您仍然可以始终获得它的公共实例。现在这就是您可以在 MainWindow 中调用实例的方式。

 public MainWindow()
    {
        InitializeComponent();
        DataContext =  CounterModel.Instance;
    }

在您看来,您相应地进行了以下更改,

<TextBlock Text="{Binding CounterValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="100" Height="20"></TextBlock>
<Button Command="{Binding startCommand}" Content="Button" HorizontalAlignment="Left" Margin="472,230,0,0" VerticalAlignment="Top" Width="75"/>

ICommand 看起来不错,所以我没有将它添加为答案的一部分。请让我知道该方法是否适合您。


推荐阅读