如何使用DataBinding使TextBlock更新文本

时间:2018-06-17 08:06:46

标签: c# .net mvvm data-binding viewmodel

所以我似乎陷入了一个循环(没有双关语意)。 我创建了我的视图,其中包含一个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();
        }
    }

我现在的问题是,当我点击我的开始按钮时它没有做任何事情......或者它很好但是我的文本属性没有正常更新,该值不对应于计时器tick事件分配给它的新值。 我尝试实现接口INotifyPropertyChanged,但我不能这样做。

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

因为OnPropertyChanged然后需要是静态的,这又会让我陷入一个全新的兔子,我不应该开始。

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

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

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

不删除Start()

中的静态修改器

是的,我确实设置了DataContext

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

1 个答案:

答案 0 :(得分:0)

我理解你的情景。但是你的Start()的可访问性不是更多的设计问题吗?通过实现单例模式以在每次调用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看起来很好,所以我没有将其添加为答案的一部分。如果方法适合你,请告诉我。