c# - WPF DependencyProperty 抛出 InvalidOperationException

标签 c# wpf wcf wpf-controls wpf-4.0

我正在尝试设置一个由 WCF 回调线程更新的依赖属性。
MainWindow.xaml 上有一个绑定(bind)到此属性的 ProgressBar:

MainWindow.xaml

<ProgressBar Name="ProgressBar" Value="{Binding Progress, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />

MainWindow 有一个 DemoModule 实例,定义如下:

DemoModule.xaml.cs

/// <summary>
///     Interaction logic for DemoModule.xaml
/// </summary>
public partial class DemoModule : UserControl, INotifyPropertyChanged
{
    public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register("Progress", typeof(int), typeof(DemoModule));        
    public event ProgressEventHandler ProgressChanged;
    public event PropertyChangedEventHandler PropertyChanged;

    public int Progress
    {
        get { return (int)GetValue(ProgressProperty); }
        set { SetValue(ProgressProperty, value); }  // setter throws InvalidOperationException "The calling thread cannot access this object because a different thread owns it"
    }

    /// <summary>
    ///     Initializes a new instance of the <see cref="DemoModule" /> class.
    /// </summary>
    public DemoModule()
    {
        InitializeComponent();
        ProgressChanged += OnProgressChanged;
    }

    /// <summary>
    /// Called when [progress changed].
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="args">The <see cref="ProgressChangedEventArgs" /> instance containing the event data.</param>
    public void OnProgressChanged(object sender, ProgressChangedEventArgs args)
    {
        Debug.WriteLine("Current Thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Debug.WriteLine("Current Dispatcher Thread: {0}", Application.Current.Dispatcher.Thread.ManagedThreadId);

        if (ProgressChanged == null) return;

        Debug.WriteLine("ProgressChangedEventArgs.Current: " + args.Current);
        Progress = Convert.ToInt32(args.Current * 100);
        OnPropertyChanged("Progress");
    }

    /// <summary>
    /// Called when [property changed].
    /// </summary>
    /// <param name="propertyName">Name of the property.</param>
    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        Trace.WriteLine("Property " + propertyName + " changed. Value = " + Progress);
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

}

Progress.set() 由于线程亲和性而抛出异常。
我该如何解决这个问题?

更新 1

这据称是线程安全的,但没有效果:

public int Progress
{
    get
    {
        return Dispatcher.Invoke((() => (int)GetValue(ProgressProperty))); 
    }
    set
    {
        Dispatcher.BeginInvoke((Action)(() => SetValue(ProgressProperty, value)));
    }
 }

更新 2

我的 DemoModule.xaml.cs 有一个对实现 WCF 回调方法 OnUpdateProgress 的客户端库的引用:

InstallerAgentServiceClient.cs

public void OnUpdateProgress(double progress)
        {
            //Debug.WriteLine("Progress: " + progress*100 + "%");
            var args = new ProgressChangedEventArgs(progress, 1, "Installing");
            _installModule.OnProgressChanged(this, args);
        }

上面的_installModule对象是DemoModule的实例。

更新 3

从 WCF 客户端库中删除 [CallBackBehavior] 属性后,似乎不再存在线程同步问题。我可以按如下方式更新主窗口中的进度条:

DemoModule.xaml.cs

public void OnProgressChanged(object sender, ProgressChangedEventArgs args)
{
    Progress = Convert.ToInt32(args.Current * 100);
    var progressBar = Application.Current.MainWindow.FindName("ProgressBar") as ProgressBar;
    if (progressBar != null)
        progressBar.Value = Progress;
}

最佳答案

您需要通过 UI 线程更新您的 DepedencyProperty。使用:

Application.Current.Dispatcher.BeginInvoke(Action)

或者:

Application.Current.Dispatcher.Invoke(Action)

关于c# - WPF DependencyProperty 抛出 InvalidOperationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22998557/

相关文章:

c# - WCF:如何阻止 myServiceHost.Close() 处理 myServiceHost 对象?

c# - 基于自定义属性的 IHostBufferPolicySelector

c# - 在 LINQ 中查询子集合

wpf - 实体类实现的IDataErrorInfo

c# - 如何从 DataTemplate 派生一个新类,然后用它代替 DataTemplate?

visual-studio - 如何为“附加到进程”对话框显示WCF服务“title”

c# - SQL事务对WCF事务的影响

c# - MVC5管理账户默认错误信息 "Incorrect password."如何修改?

c# - 如何获取远程机器上的任务历史记录?

wpf - 如何将 ControlTemplate 中的控件属性数据绑定(bind)到包含该模板的控件的窗口的数据上下文?