Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF DependencyProperty引发InvalidOperationException_C#_Wpf_Wcf_Wpf Controls_Wpf 4.0 - Fatal编程技术网

C# WPF DependencyProperty引发InvalidOperationException

C# WPF DependencyProperty引发InvalidOperationException,c#,wpf,wcf,wpf-controls,wpf-4.0,C#,Wpf,Wcf,Wpf Controls,Wpf 4.0,我正在尝试设置由WCF回调线程更新的依赖项属性。 MainWindow.xaml上有一个ProgressBar绑定到此属性: main window.xaml <ProgressBar Name="ProgressBar" Value="{Binding Progress, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" /> 更新2 My DemoModule.xaml.cs引用了一个客户端库,该库实现了UpdateProgr

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

main window.xaml

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

My DemoModule.xaml.cs引用了一个客户端库,该库实现了UpdateProgress上的WCF回调方法:

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

}
public void OnUpdateProgress(double progress)
        {
            //Debug.WriteLine("Progress: " + progress*100 + "%");
            var args = new ProgressChangedEventArgs(progress, 1, "Installing");
            _installModule.OnProgressChanged(this, args);
        }
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;
}
上面的
\u installModule
对象是
DemoModule
的实例

更新3

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

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

}
public void OnUpdateProgress(double progress)
        {
            //Debug.WriteLine("Progress: " + progress*100 + "%");
            var args = new ProgressChangedEventArgs(progress, 1, "Installing");
            _installModule.OnProgressChanged(this, args);
        }
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线程更新DependencyProperty。使用:

Application.Current.Dispatcher.BeginInvoke(Action)
或:


我建议使用IProgress接口。 对我来说很有魅力,而且很容易使用。 在progressbarVM中添加

public double Actualprogress
{
get { return (double)GetValue(ActualprogressProperty); }
set { SetValue(ActualprogressProperty, value); }
}
public static readonly DependencyProperty ActualprogressProperty =
DependencyProperty.Register("Actualprogress", typeof(double), typeof(ProgressBar), 
new PropertyMetadata(0.0));
然后使用wait将您的方法作为asyn任务调用,如下所示:

var progress = new Progress<double>(progressPercent => 
progressBarVM.progressBar.Actualprogress = progressPercent);
Parser parser = new Parser();
ModelVMResult result = await Task.Run(() => parser.Parse(filename,progress));
var progress=新进度(progressPercent=>
progressBarVM.progressBar.Actualprogress=progressPercent);
Parser Parser=新解析器();
ModelVMResult=wait Task.Run(()=>parser.Parse(文件名,进度));
然后在方法“parse”中只需执行以下操作:

浮动阈值=0.0f;
for(int i=0;i=阈值)
{progress.Report(prog+=1);threshold+=count/100.0f;}
这个.Readline(reader,i);
}
当然,您需要将xaml progressbar.Value绑定到ProgressbarVM.Actualprogress。
然后,您的progressbar将更新,并且在此过程中,您的应用程序仍将响应。

为什么要实施INotifyPropertyChanged?如果您绑定到DependencyProperties,则不需要它。我想我必须同时做这两件事。还在这里学习。我在WPF的第一周。实际上,VM实现有两种可能性。第一个是实现INotifyPropertyChanged接口。第二个是从DependencyObject继承,并将属性声明为依赖属性。第一个通常是最合适的。但是ViewModel不应该继承WPF控件,如UserControl。。。好吧,除了一些特定的情况。由于我们不能进行多重继承,我想我必须坚持使用INPC。显示您的WCF调用以更新进度条。我尝试了,并且
this.Dispatcher.Invoke()
。两者都没有对ProgressBar产生任何影响。