0

我在 UserControl 的 DependencyProperty 和 TextBlock 的 DependencyProperty 上使用 DataBinding。我将它们绑定到属性 TestValue。首先我用 TestValue="TestValue set first time!" 初始化 TestValue 这样可行!UserControl 和 TextBlock 都得到更新。
然后,通过 DispatcherTimer,我每秒向 TestValue 写入一个随机值,这不起作用。TextBlock 得到更新,但 UserControl 没有。

这是我的 MainWindow 代码:

//MainWindow.cs
public partial class MainWindow : Window
{
    private MainWindowViewModel viewModel;

    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = this.viewModel = new MainWindowViewModel()
        {
            TestValue = "TestValue set first time!",
        };
    }
}

//MainWindow.xaml
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local ="clr-namespace:RhinoTouchUIwpf;assembly="
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="RhinoTouchUIwpf.MainWindow"
    SizeToContent="WidthAndHeight">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="auto"/>
    </Grid.ColumnDefinitions>
    <local:UserControl1 OperationName="{Binding TestValue, Mode=OneWay}" Grid.Row="0"/>
    <TextBlock Text="{Binding TestValue, Mode=OneWay}" FontSize="15" Grid.Row="1" />
</Grid>

这是用户控件的代码:

//UserControl1.cs
public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    public static DependencyProperty MyDependencyProperty =DependencyProperty.Register("OperationName", typeof(String), typeof(UserControl1), new UIPropertyMetadata(null, MyDependencyPropertyChangedHandler));

    private static void MyDependencyPropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        ((UserControl1)sender).OperationName = (String)e.NewValue;
        ((UserControl1)sender).NumberLabel.Text = (String)e.NewValue;
    }
    public String OperationName
    {
        get { return (string)(this.GetValue(MyDependencyProperty)); }
        set { this.SetValue(MyDependencyProperty, value); }
    }
}

//UserControl1.xaml
<UserControl
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:RhinoTouchUIwpf" x:Class="RhinoTouchUIwpf.UserControl1" 
         mc:Ignorable="d">

<Border BorderThickness="1" BorderBrush="Blue" x:Name="ControlBorder">
    <Grid Background="AliceBlue">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock x:Name="NumberLabel" FontSize="20"  Text="0" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Border>

这是 MainWindowViewModel 的代码,我每秒由 DispatcherTimer 更改其属性。

public class MainWindowViewModel : ViewModelBase
{
    DispatcherTimer dispatcherTimer; 

    public MainWindowViewModel()
    {
        dispatcherTimer = new DispatcherTimer();
        dispatcherTimer.Tick += Dispatcher_Tick;
        dispatcherTimer.Interval = TimeSpan.FromSeconds(1);
        dispatcherTimer.IsEnabled = true;
    }

    void Dispatcher_Tick(object sender, EventArgs e)
    {
        this.TestValue = "" + DateTime.Now.Millisecond;
    }

    private String _TestValue;

    public String TestValue
    {
        get { return _TestValue; }
        set
        {
            _TestValue = value;
            OnPropertyChanged("TestValue");
        }
    }

    private static readonly MainWindowViewModel NullInstance = null;

}

public abstract class ViewModelBase : System.ComponentModel.INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this,
                new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

TextBlock 的文本每秒都会更改,而 UserControl1 的文本不会。
我究竟做错了什么?

4

1 回答 1

0

您遇到的问题是您的这行代码PropertyChangedCallback

((UserControl1)sender).OperationName = (String)e.NewValue;

这里的问题是事件处理程序会通知您对同一属性的新更改。当你进入这个函数时,它来自:

set { this.SetValue(MyDependencyProperty, value); }

有效地进入一个无限循环(依赖属性系统检测并停止对该函数的进一步调用)。删除该行将解决您的问题。

另一方面,PropertyChangedCallback如果您在 XAML 中定义它,则可以完全摆脱它:

// On your UserControl element, add a x:Name="uc"
<TextBlock x:Name="NumberLabel" FontSize="20"  
           Text="{Binding OperationName, ElementName=uc, FallbackValue=0}" 
           Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center" 
           VerticalAlignment="Center"/>

这是完整的 UserControl1.xaml

<UserControl x:Class="WpfApplication1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" x:Name="uc"
             d:DesignHeight="300" d:DesignWidth="300">
    <Border BorderThickness="1" BorderBrush="Blue" x:Name="ControlBorder">
        <Grid Background="AliceBlue">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <TextBlock x:Name="NumberLabel" FontSize="20"  
                        Text="{Binding OperationName, ElementName=uc, FallbackValue=0}" 
                        Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center" 
                        VerticalAlignment="Center"/>
        </Grid>
    </Border>
</UserControl>
于 2013-08-06T15:27:53.813 回答