Windows Phone数据绑定:跨线程

本文关键字:线程 数据绑定 Phone Windows | 更新日期: 2023-09-27 18:16:09

我们在Windows phone(使用xaml)上有一个数据绑定问题。我创建了一个简单的示例,它应该允许再现这个问题。这是我们的模型类:

public class Data : INotifyPropertyChanged
{
    private int value = 0;
    public int Value
    {
        get
        {
            return value;
        }
        set
        {
            this.value = value;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Value"));
            }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public Data()
    {
        var t = new Thread(new ThreadStart(() =>
        {
            while (true)
            {
                Thread.Sleep(2000);
                Value += 1;
            }
        }));
        t.IsBackground = true;
        t.Start();
    }
}

使用一个线程来更新value-property并触发PropertyChanged-event。

现在我想把这个值属性绑定到一个gui控件:

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <TextBlock Text="{Binding Path=Value}" />
    </Grid>
    public MainPage()
    {
        InitializeComponent();
        DataContext = new Data();
    }

当值第一次更改时(并且触发PropertyChanged-event),数据绑定系统尝试复制data的值。值为TextBlock。文本,这会导致无效的跨线程异常,因为此事件没有在ui线程上触发。

我的问题:.NET数据绑定框架不应该认识到我绑定到一个ui控件并执行线程切换本身?我知道我可以简单地使用调度程序在主线程上触发PropertyChanged-event,但我想让我的模型类与gui组件分开。这个问题有更好的解决办法吗?我无法使用DependencyObject方法,因为我们的核心项目(包含模型类)应该在Windows Phone和Android上运行,而Android不支持System.Windows-namespace。

Windows Phone数据绑定:跨线程

解决这个问题的一种方法是在视图模型上存储对调度程序的引用,并且仅在它不为空时使用它来执行属性更改事件。然后你可以在VM的构造函数中设置dispatcher属性。

我这样做:

public event PropertyChangedEventHandler PropertyChanged;
    private void PropertyEventChanged(string propertyName)
    {
        if (PropertyChanged == null) return;
        if (Application.OpenForms.Count > 0 && Application.OpenForms[0].InvokeRequired)
            Application.OpenForms[0].Invoke(new MethodInvoker(() => PropertyChanged(this, new PropertyChangedEventArgs(propertyName))));
        else
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }