【问题标题】:Windows Phone data binding: cross-threadWindows Phone 数据绑定:跨线程
【发布时间】:2011-11-30 18:57:22
【问题描述】:

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();
    }
}

它使用线程来更新值属性并触发 PropertyChanged 事件。

现在我想将此值属性绑定到 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 事件被触发),数据绑定系统尝试将 Data.Value 的值复制到 TextBlock.Text,这会导致无效的跨线程异常,因为该事件不是在 ui 线程上触发。

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

【问题讨论】:

    标签: c# windows-phone-7 data-binding multithreading


    【解决方案1】:

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

    【讨论】:

    • Deployment.Current.Dispatcher
    • 正如我在原始问题中发布的那样,我们确实知道这是一种可能性。在完整的 .NET 框架中,不需要使用调度程序,因为数据绑定会自动切换到主线程。我想知道我是否(或如何)在 Windows 手机(或用于 android 的 silverlight)上实现这种行为。
    • @Will 部署在 System.Windows 中,这不是一个可能的解决方案:msdn.microsoft.com/en-us/library/…
    • @Will 请阅读我的问题:“我无法使用 DependencyObject 方法,因为我们的核心项目(包含模型类)应该在 Windows Phone 和 Android 上运行,而 Android 不支持System.Windows 命名空间。” (这也适用于 System.Windows.Deployment)
    • @DominikvonWeber:啊……我的错。好的,所以静态引用不起作用。包装调用并使用依赖注入呢?
    【解决方案2】:

    我喜欢这样:

    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));
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-01
      • 1970-01-01
      相关资源
      最近更新 更多