首页 > 解决方案 > WPF 数据绑定在初始化后不起作用。没有绑定错误

问题描述

我的View和之间的数据绑定有问题ViewModel。绑定仅在初始化时运行,然后它们不会更新。代码按预期运行,每个输出窗口都没有绑定错误,但 UI 上的绑定不会更新。

程序设置:

我尝试过的事情:

每个人都将运行代码,但不会更新 UI。我留下了一些我在程序中尝试过的代码,用于BackgroundWorkerDelegate voidDispatcher.BeginInvoke。我写了几个程序,从来没有遇到过这个问题。我创建程序时是否设置错误?

更新:Visual Studio 2019 似乎存在问题。这可能仅在我的版本上,因为我编写的其他程序不再工作。这通常可以按预期运行。

UserControl 我正在尝试进行简单的绑定。我Textbox在底部创建了一个Mode=TwoWay以查看是否TextBlock会更新。

<UserControl x:Class="MRC.Module.ModStatus.Views.ModStatusManagerView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:MRC.Module.ModStatus.Views"
             
             xmlns:prism="http://prismlibrary.com/"  
             
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:cconv="clr-namespace:MRC.Framework.Core.Data.Converters;assembly=MRC.Framework.Core"
             
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" >
    <UserControl.Resources>
        <cconv:RemoveSpacesConverter x:Key="IntToStringConvert"/>
    </UserControl.Resources>
    <Grid>
        <Grid.Background>
            <SolidColorBrush Color="#222222"/>
        </Grid.Background>
        
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="3*"/>
            </Grid.ColumnDefinitions>
         
            <Border BorderBrush="DodgerBlue" BorderThickness="1">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>

                    <Grid Grid.Row="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
                        <Border BorderThickness="1" BorderBrush="DodgerBlue" VerticalAlignment="Stretch" Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}}">
                            <StackPanel VerticalAlignment="Stretch">
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                    <Button Height="20" Margin="0,6" Content="{Binding StartStop}" Width="100"
                                        >
                                        <i:Interaction.Triggers>
                                            <i:EventTrigger EventName="Click" >
                                                <i:InvokeCommandAction Command="{Binding ProgressCommand}" />
                                            </i:EventTrigger>
                                        </i:Interaction.Triggers>
                                    </Button>
                                  
                                </StackPanel>
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                    <TextBlock  Margin="5,0"  HorizontalAlignment="Center" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.Health, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToStringConvert}}" FontSize="16" Foreground="White"/>
                                    <TextBlock  Margin="5,0"  Text="{Binding TestingText}" Foreground="White" FontSize="16" AutomationProperties.Name="TestText"/>
                                </StackPanel>
                                <!--
                                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.Health, UpdateSourceTrigger=PropertyChanged}"
                                -->
                                <ProgressBar Maximum="100" Minimum="0"
                                      VerticalAlignment="Bottom" Height="25" Margin="5" />

                                <TextBox Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.TestingText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="16" Height="30" Margin="5" Width="100"/>
                            </StackPanel>
                          
                        </Border>
                    </Grid>
                   
                </Grid>
            </Border>

            <TextBlock HorizontalAlignment="Center" Grid.Column="1" VerticalAlignment="Center" Text="Mod Status" 
                       FontSize="30" Foreground="Black"/>
        </Grid>
    </Grid>
</UserControl>

代码背后

  public partial class ModStatusManagerView : UserControl
    {
        public ModStatusManagerView()
        {
            InitializeComponent();
            DataContext = new ModStatusManagerViewModel();
        }

       
    }

视图模型

 public class ModStatusManagerViewModel : ViewModelBase
    {

        #region Variables
        private readonly BackgroundWorker worker = new BackgroundWorker();

        private delegate void UpdateUIDelgate(string health, string Status);
        #endregion

        #region Commands
         public ICommand ProgressCommand { get; private set; }
        private void Testing(string health, string Status)
        {
            try
            {
                
            }
            catch(Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message);
            }

            
        }

        private bool CanProgressExecute()
        {
            return true;
        }
        private void Progress()
        {
            try
            {


                System.Windows.Application.Current.Dispatcher.Invoke(() => 
                {

                    Health = 0;
                    StartStop = "Stop";
                    TestingText = "Initialized";

                    for (int i = 0; i < 99; i++)
                    {
                        Health = i;
                        System.Windows.Application.Current.MainWindow.UpdateLayout();
                        System.Threading.Thread.Sleep(100);
                    }

                    TestingText = "Completed";
                    System.Windows.MessageBox.Show("Complete");

                }, System.Windows.Threading.DispatcherPriority.Render);

                /*if (!System.Windows.Application.Current.Dispatcher.CheckAccess())
                {
                    System.Windows.Application.Current.Dispatcher.BeginInvoke(
                       new UpdateUIDelgate(Testing), "Stop", "Initialized");
                    return;
                }*/


               // System.Windows.Application.Current.MainWindow.Dispatcher.BeginInvoke(
                   // new UpdateUIDelgate(Testing), "Stop", "Initialized");
                
            }
            catch(Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message);
            }       
        }


        public ICommand ProgressOffCommand { get; }
        private void ProgressOff()
        {
            System.Windows.Application.Current.Dispatcher.Invoke(() =>
            {
                StartStop = "Start";
            });
        }
        #endregion

        #region Constructor
        public ModStatusManagerViewModel()
        {
            this.ProgressCommand = new RelayCommand(Progress);
            //this.ProgressOffCommand = new RelayCommand(ProgressOff);
        }

        #endregion

        #region Properties
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set { SetProperty(ref _isEnabled, value); }
        }
        private bool _isEnabled = true;
        /// <summary>
        /// Gets or Sets the Max Health
        /// </summary>
        public string StartStop
        {
            get { return _startStop; }
            set { SetProperty(ref _startStop, value); }
        }
        private string _startStop = "Start";



        /// <summary>
        /// Gets or Sets the Max Health
        /// </summary>
        public bool IsOn
        {
            get { return _isOn; }
            set { SetProperty(ref _isOn, value); }
        }
        private bool _isOn = false;

        /// <summary>
        /// Gets or Sets the Max Health
        /// </summary>
        public double MaxHealth
        {
            get { return _maxHealth; }
            set { SetProperty(ref _maxHealth, value); }
        }
        private double _maxHealth = 100;

        /// <summary>
        /// Gets or Sets the Min Health
        /// </summary>
        public double MinHealth
        {
            get { return _minHealth; }
            set { SetProperty(ref _minHealth, value); }
        }
        private double _minHealth = 0;

        /// <summary>
        /// Gets or Sets the Min Health
        /// </summary>
        public double Health
        {
            get { return _Health; }
            set { SetProperty(ref _Health, value); }
        }
        private double _Health = 0;

        public string TestingText
        {
            get { return _testingText; }
            set { SetProperty(ref _testingText, value); }
        }
        private string _testingText = "Waiting";
        #endregion

        #region Events

        #endregion

        #region Methods
        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                while (IsOn)
                {
                    Random rnd = new Random();

                    Health = rnd.Next(0, 100);

                    System.Threading.Thread.Sleep(150);
                }
                System.Threading.Thread.Sleep(150);
            }

        }

        private void worker_RunWorkerCompleted(object sender,
                                                   RunWorkerCompletedEventArgs e)
        {
            //update ui once worker complete his work
        }
        #endregion
    }

如果有人想查看INotifyPropertyChanged

 public abstract class ViewModelBase : ModelBase
    {
        public ViewModelBase()
        {

        }
        ~ViewModelBase()
        {

        }

        public bool HasAnyErrors { get; set; }
    }

这是ModelBase那个ViewModelBase实现

 public abstract class ModelBase : BindableBase, INotifyPropertyChanged
    {
        protected ModelBase()
        {

        }
        ~ModelBase() { }

        public bool HasIssues { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public static event PropertyChangedEventHandler StaticPropertyChanged = delegate { };

        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public static void OnStaticPropertyChanged(string propertyName)
        {
            StaticPropertyChanged?.Invoke(
                typeof(ViewModelBase),
                new PropertyChangedEventArgs(propertyName));
        }
    }

这里是RelayCommand

 public class RelayCommand : ICommand
    {

        #region Private Members
        private Action _action;
        private Action<object> _actionOb;

        Action<object> _execteMethod;
        Func<object, bool> _canexecuteMethod;
        #endregion

        #region Public Events
        /// <summary>
        /// Basic Command
        /// </summary>
        public event EventHandler CanExecuteChanged = (sender, e) => { };
        #endregion

        #region Constructors
        /// <summary>
        /// Default Constructor
        /// </summary>
        /// <param name="action"></param>
        public RelayCommand(Action action)
        {
            _action = action;
        }

        /*public RelayCommand(System.Collections.ObjectModel.ObservableCollection<Frames.Model.Category> category, Action<object> action)
        {
            _actionOb = action;
        }*/


        /// <summary>
        /// Default Constructor that passes an object
        /// </summary>
        /// <param name="execteMethod"></param>
        /// <param name="canexecuteMethod"></param>
        public RelayCommand(Action<object> execteMethod, Func<object, bool> canexecuteMethod)
        {
            _execteMethod = execteMethod;
            _canexecuteMethod = canexecuteMethod;
        }

        /// <summary>
        /// Default Constructor that determines if an action can execute before executing
        /// </summary>
        /// <param name="action"></param>
        /// <param name="CanExecute"></param>
        public RelayCommand(Action action, bool CanExecute)
        {
            if (CanExecute)
                return;
            _action = action;
        }

        public RelayCommand(Action<object> action, bool CanExecuteOb)
        {
            _actionOb = action;
        }
        #endregion

        #region Command Methods
        /// <summary>
        /// Returns True if bool Parameter is not busy
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public bool CanExecute(object parameter)
        {
            if (parameter != null)
            {
                try
                {
                    if ((bool)parameter)
                        return false;
                    return true;
                }
                catch
                {
                    return true;
                }
            }
            else
            {
                return true;
            }


        }

        public bool CanExecuteOb(object parameter)
        {
            return true;
        }

        /// <summary>
        /// Executes an Action that is not busy
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            Task.Run(async () =>
            {
                _action();
            });
        }
        /// <summary>
        /// Executes an Action that is not busy with a <href="Param">
        /// </summary>
        /// <param name="param"></param>
        public void ExecuteOb(object param)
        {
            Task.Run(async () =>
            {
                _actionOb(param);
            });
        }
        #endregion

    }

标签: c#wpfxamlmvvmprism

解决方案


更新: 的功能似乎SetProperty已停止工作。

我将我的属性从

 public string TestingText
        {
            get { return _testingText; }
            set { SetProperty(ref _testingText, value);}
        }
        private string _testingText = "Testing";

 public string TestingText
        {
            get { return _testingText; }
            set
            {
                if (_testingText == value)
                    return;
                _testingText = value;
                OnPropertyChanged("TestingText");
            }
        }
        private string _testingText = "Testing";

现在一切正常。


推荐阅读