简单的数据绑定无法正常工作

时间:2011-01-25 06:47:48

标签: c# .net wpf xaml data-binding

我是WPF的新手,我正在尝试制作一个简单的应用程序,一个秒表。如果我没有进行数据绑定,它可以正常工作。这是我的XAML。

<Window x:Class="StopWatch.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="clr-namespace:StopWatch"
    Title="MainWindow" Height="318" Width="233">
<Window.Resources>
    <s:StopWatchViewModel x:Key="swViewModel" x:Name="swViewModel"></s:StopWatchViewModel>
</Window.Resources>
<Grid DataContext="{StaticResource swViewModel}"> 
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="128*" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="1" Height="49" HorizontalAlignment="Left" Margin="42,50,0,0" Name="txtTime" Text="{Binding Path=Message}" VerticalAlignment="Top" Width="147" FontSize="20" TextAlignment="Center" />
    <Button Content="Start" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="12,15,0,0" Name="startBtn" VerticalAlignment="Top" Width="58" Click="startBtn_Click" />
    <Button Content="Stop" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="76,15,0,0" Name="stopBtn" VerticalAlignment="Top" Width="58" Click="stopBtn_Click" />
    <Button Content="Reset" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="140,15,0,0" Name="resetBtn" VerticalAlignment="Top" Width="59"/>
</Grid>

,这是MainWindow中的代码

public partial class MainWindow : Window
{
    private StopWatchViewModel stopwatch;

    public MainWindow()
    {
        InitializeComponent();
        stopwatch = new StopWatchViewModel();
    }

    private void startBtn_Click(object sender, RoutedEventArgs e)
    {
        stopwatch.Start();
    }

    private void stopBtn_Click(object sender, RoutedEventArgs e)
    {
        stopwatch.Stop();
    }
}

这是StopWatchViewModel.cs中的代码

class StopWatchViewModel : INotifyPropertyChanged
{
    private DispatcherTimer timer;
    private Stopwatch stopwatch;
    private string message;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Message
    {
        get
        {
            return message;
        }
        set
        {
            if (message != value)
            {
                message = value;
                OnPropertyChanged("Message");
            }
        }
    }

    public StopWatchViewModel()
    {
        timer = new DispatcherTimer();
        stopwatch = new Stopwatch();
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
        stopwatch.Reset();
    }

    public void Start()
    {
        stopwatch.Start();
    }

    public void Stop()
    {
        stopwatch.Stop();
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        Message = stopwatch.Elapsed.ToString(); // Doesn't work.
        // Message = "hello"; does not work too!
    }

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

我不知道我哪弄错了。

编辑:我搞定了。所以这是任何人参考的工作代码。

XAML,将原始内容更改为此

<Window x:Class="StopWatch.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:StopWatch"
Title="MainWindow" Height="318" Width="233">
<Grid> // partial code

并在后面的代码中,根据Erno的建议更改构造函数。

public MainWindow()
    {
        InitializeComponent();
        viewModel = new StopWatchViewModel();
        this.DataContext = viewModel;
    }

谢谢你们!

3 个答案:

答案 0 :(得分:4)

您的问题是,您没有任何机制让WPF知道您的属性已更新。基本上你有两个选择:

  1. 将消息转换为依赖属性。
  2. 实施INotifyPropertyChanged,以便让GUI知道消息何时更新。
  3. 为了确保您拥有让INotifyPropertyChanged工作的所有部分,请检查您是否完成了所有这些:

    1. 定义活动PropertyChanged
    2. 制作一个私有NotifyPropertyChanged方法来举起活动。此方法应采用字符串参数(属性的名称)并引发如下事件:PropertyChanged(this, new PropertyChangedEventArgs(<nameofproperty>)。制作此方法的原因是将空检查和调用详细信息放在一个位置。
    3. 在属性设置器中,在值更改后,使用属性的正确名称(区分大小写)调用NotifyPropertyChanged

答案 1 :(得分:3)

只需像这样替换你的Message属性,它就会起作用:

 public string Message
 {
     get { return (string)GetValue(MessageProperty); }
     set { SetValue(MessageProperty, value); }
 }

 public static readonly DependencyProperty MessageProperty =
     DependencyProperty.Register("Message", typeof(string), 
     typeof(MainWindow), new UIPropertyMetadata(String.Empty));
在发布我的解决方案后

编辑我注意到您已将所有代码更改为ViewModel解决方案...随意忽略或返回到您的第一组代码。

在新代码中,您将创建ViewModel的两个实例,一个在代码中,另一个在资源中。这是不好的,因为你正在操作代码中的那个并绑定到资源中的那个(xaml)

修改 将构造函数更改为:

public MainWindow()
{
    InitializeComponent();
    stopwatch = new StopWatchViewModel();
    this.DataContext = stopwatch;
}

这就是全部

答案 2 :(得分:1)

如果未正确实现INotifyPropertyChanged,则不会注意到对属性的更改。所以你应该先做。也许你早些时候错过了什么。