mc:Ignorable="d" WindowStartupLocation="CenterScreen" Title="MainWindow" Style="{StaticResource BaseWindowStyle}">    <Window.Resources>
        <ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="MyLightMode">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="api:LightMode"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>        <ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="MySortingLogStyle">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="e:ESortingLogStyle"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>        <valueConverter:ChannelValueConverter x:Key="ChannelValueConverter"/>
        <valueConverter:SortingLogStyleValueConverter x:Key="SortingLogStyleValueConverter"/>
    </Window.Resources>    <i:Interaction.Triggers>
        <prism:InteractionRequestTrigger SourceObject="{Binding ShowMessageBoxRequest}">
            <utils:CustomPopupWindowAction CenterOverAssociatedObject="True" IsModal="True">
                <prism:PopupWindowAction.WindowContent>
                    <dlg:ShowMessageUserControl/>
                </prism:PopupWindowAction.WindowContent>
            </utils:CustomPopupWindowAction>
        </prism:InteractionRequestTrigger>        <prism:InteractionRequestTrigger SourceObject="{Binding ProcessSortingUIRequest}">
            <ta:ProcessSortingUITriggerAction/>
        </prism:InteractionRequestTrigger>
    </i:Interaction.Triggers>    <Grid>
        <Viewbox Stretch="Fill"  >
            <Canvas  Height="648" Width="1024">
                <Label  Content="{Binding CurrentErrorInfo}" Canvas.Top="597" Background="Red" Foreground="White" Width="1013" Height="36">
                    <Label.Style>
                        <Style TargetType="{x:Type Label}" BasedOn="{StaticResource ContentAlignmentLabelStyle}">
                            <Setter Property="Padding" Value="3,3"/>
                            <Style.Triggers>
                                <Trigger Property="Content" Value="{x:Null}">
                                    <Setter Property="Visibility" Value="Collapsed"/>
                                </Trigger>
                                <Trigger Property="Content" Value="">
                                    <Setter Property="Visibility" Value="Collapsed"/>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Label.Style>
                </Label>
                        </Canvas>
                    </TabItem>
                </TabControl>
                <StackPanel Visibility="{Binding AutoTagSelfCheckingProgressVisibility,UpdateSourceTrigger=PropertyChanged}" Orientation="Horizontal" Background="White" Canvas.Left="1" Canvas.Top="515" Width="1023" Height="82">
                    <Label Content="  自检中..." Style="{StaticResource ContentAlignmentLabelStyle}" />
                    <ProgressBar Height="42" Value="{Binding AutoTagSelfCheckingProgressValue, UpdateSourceTrigger=PropertyChanged}" Width="882" Minimum="0" Maximum="100" Margin="0,20" Foreground="Blue"/>
                </StackPanel>
            </Canvas>
        </Viewbox>
    </Grid>
</base:BaseWindow>...:INotifyPropertyChanged
{
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
// 是不是invoke已经可以保证线程安全了?
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
        }        string currentErrorInfo;
        public string CurrentErrorInfo
        {
            get
            { return currentErrorInfo; }
            set
            {
                if (currentErrorInfo != value)
                {
                    Interlocked.Exchange(ref currentErrorInfo, value);
                    OnPropertyChanged(nameof(CurrentErrorInfo));
                }
            }
        }        object autoTagSelfCheckingProgressVisibility = Visibility.Collapsed;
        public Visibility AutoTagSelfCheckingProgressVisibility
        {
            get
            { return (Visibility)autoTagSelfCheckingProgressVisibility; }
            set
            {
                if ((Visibility)autoTagSelfCheckingProgressVisibility != value)
                {
                    Interlocked.Exchange(ref autoTagSelfCheckingProgressVisibility, value);
                    OnPropertyChanged(nameof(AutoTagSelfCheckingProgressVisibility));
                }
            }
        }
比如
一个是绑定改变label文字的 CurrentErrorInfo
一个是改变进度条控件显示的AutoTagSelfCheckingProgressVisibility
目前都是直接在ViewModel里某个线程里直接修改绑定值了,倒是一直也没出问题,                ThreadPool.QueueUserWorkItem(obj =>
                {
                       CurrentErrorInfo="111";                        AutoTagSelfCheckingProgressVisibility = Visibility.Visible;
               });
是不是最好还是这样?:
                Application.Current.Dispatcher.Invoke((Action)(()=>{
                    AutoTagSelfCheckingProgressVisibility = Visibility.Visible;
                }));
有没有必要?为什么不用也不会出错,报跨线程处理UI的错误        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
// 是不是invoke已经可以保证线程安全了?
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
        }
另外,绑定Visibility属性时,如何设置默认值Collapsed,否则程序启动控件会显示,直到绑定值Collapsed生效后消失
        public MainWindow()
        {
            InitializeComponent();            this.ContentRendered += MainWindow_ContentRendered;
        }        private void MainWindow_ContentRendered(object sender, EventArgs e)
        {
            this.DataContext = new MainViewModel();Visibility="{Binding AutoTagSelfCheckingProgressVisibility,UpdateSourceTrigger=PropertyChanged}" 

解决方案 »

  1.   


            public event PropertyChangedEventHandler PropertyChanged;
            public void OnPropertyChanged(string propertyName)
            {
                App.Current?.Dispatcher?.Invoke((Action)(() =>
                {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                }));
            }
    还是在这里加了一个,为了PropertyChanged订阅内部触发保险起见
      

  2.   

    MainViewModel  里面初始化  Visibility 属性就行了。
      

  3.   

    object autoTagSelfCheckingProgressVisibility = Visibility.Collapsed;
            public Visibility AutoTagSelfCheckingProgressVisibility
    -》为什么要用object而不用Visibility 。
    UI控件和属性不同,操作的只是一个WPF中的属性而已,WPF中的属性会映射到对应的.net属性,自然不会出错。如果使用跨线程去操作WPF中的一个Button,比如:
    Task.Run(() =>
                {
                     // 操作button
                });
    会报UI错误,因为button不是由工作者线程创建的。
      

  4.   


    因为 Interlocked.Exchange原子操作的参数必须是可引用对象,否则报错,我会在多线程里读写这个值PropertyChanged内部机制不是很了解,网上看过一篇文章试图去从.net源码查看其何时注册订阅和执行改变,但不幸的是那文章太监了,藏的太深作者没往下走了,我就怕PropertyChanged最终执行还是去调用UI控件,类似txtABC.txt="111"
      

  5.   

    你既然实现了INotifyPropertyChanged,为什么还要用invoke啊,
    有线程安全的考虑的话,应该是在cs文件中考虑吧。要不然还考虑什么前后端分离
      

  6.   


    因为 Interlocked.Exchange原子操作的参数必须是可引用对象,否则报错,我会在多线程里读写这个值PropertyChanged内部机制不是很了解,网上看过一篇文章试图去从.net源码查看其何时注册订阅和执行改变,但不幸的是那文章太监了,藏的太深作者没往下走了,我就怕PropertyChanged最终执行还是去调用UI控件,类似txtABC.txt="111"
    一般使用PropertyChanged就不会进行txtABC.txt="111"这种赋值方式,如果这样,那就不要用binding了,也就不存在view与viewmodel的分离了。
      

  7.   


    不是手动去自己赋值,而且想知道binding后,PropertyChanged的内部机制最后是如何实际更新UI属性的,.net源码里不知道是否能看出来
      

  8.   

    列表绑定observablecollection后也是不能在线程中进行列表的add和remove的。
      

  9.   


    不是手动去自己赋值,而且想知道binding后,PropertyChanged的内部机制最后是如何实际更新UI属性的,.net源码里不知道是否能看出来
    估计看不出来的
      

  10.   


    不是手动去自己赋值,而且想知道binding后,PropertyChanged的内部机制最后是如何实际更新UI属性的,.net源码里不知道是否能看出来
    估计看不出来的那先这样把,加个保险点,性能上也没啥损失
      

  11.   

    现在把这个还是去掉了,多重invoke毫无意义,只要保证调用方式是
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    而不是
          PropertyChanged?(this, new PropertyChangedEventArgs(propertyName));
                        
      

  12.   


    那只是改变 VM 的属性,你又没有操作 UI 控件,纠结 UI 干什么呢?如果要纠结 Control.Invoke/BeginInvoke,那么你就不要使用你的那个所谓的 MVVM 框架了,说明它设计有问题。它自然是需要处理 control.BeginInvoke/Invoke,跟你完全无关。
      

  13.   

    你认为 WPF 的 binding 机制设计有问题?
      

  14.   

    AutoTagSelfCheckingProgressVisibility 本来就是一个没有必要出现的 VM 属性。VM 里边应该是体现各种业务属性,不是为了 UI 而 UI 的属性。所以进度条是否可见,完全可以通过业务逻辑来设计,通过 Convertor 来将业务数据转变为可见性。