簡體   English   中英

列表中的按鈕數據綁定行為不正確

[英]Button databinding in list doesn't behave correctly

我是MVVM的新手,但有一個奇怪的行為,但未能成功解決:我通過列表顯示了一些按鈕(和其他元素):

我的應用程序GUI

即使其他元素對數據綁定的行為正確(在對象更改狀態時更新),按鈕也只能正確停用,而不會相對於命令狀態重新激活:我必須單擊GUI刷新並獲取更新的和正確的狀態。

我在StackOverflow上發現可以使用以下方法解決此問題:

CommandManager.InvalidateRequerySuggested();

但是我沒有找到如何使用它的方法:或者這沒有任何影響,或者(當放置在我的RelayCommand中-無論如何這都不是一個好主意)它為按鈕,但會使其他項目行為不正確。

請找到我的XAML:

<DataTemplate x:Key="ProjectTemplate">
     <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" Margin="0, 2, 0, 2">
          <ProgressBar Value="{Binding BuildProgress}" Width="60" Height="15"/>
          <TextBox Text="{Binding Label}" MinWidth="120" IsEnabled="{Binding IsLabelAvailable}" Margin="5,0,0,0" />
          <CheckBox Content="Archive" IsChecked="{Binding ToBeArchived}" IsEnabled="{Binding IsAvailable}" Margin="5,4,0,0" />
          <Button Content="Build" Command="{Binding Path=BuildCommand}" Margin="5,0,0,0" />
          <Button Content="Rebuild" Command="{Binding Path=RebuildCommand}" Margin="5,0,0,0" />
          <Button Content="Publish" Command="{Binding Path=PublishCommand}" Margin="5,0,0,0" />
          <TextBlock Text="{Binding Status}" Margin="10,0,0,0" />
     </StackPanel>
</DataTemplate>
<ListBox Grid.Row="0" ItemsSource="{Binding Path=Projects}" ItemTemplate="{StaticResource ProjectTemplate}" >
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True" >
                        <Setter Property="FontWeight" Value="Normal" />
                        <Setter Property="Background" Value="Transparent" />
                        <Setter Property="Foreground" Value="Black" />
                    </Trigger>
                </Style.Triggers>
                <Style.Resources>
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
                </Style.Resources>
            </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

我的ViewModel:

    public ObservableCollection<Project> Projects
    {
        get
        {
            return _projects;
        }

        set
        {
            if (_projects == value)
                return;

            _projects = value;
            OnPropertyChanged("Projects");
        }
    }

而我的模特:

    private readonly Lazy<ICommand> _lazyRebuildCommand;
    private bool _isAvailable;

    public Project()
    {
        IsAvailable = true;
        _lazyRebuildCommand = new Lazy<ICommand>(() =>
            new RelayCommand(
                param => BuildProject(true),
                param => IsAvailable
                ));
    }

    public ICommand RebuildCommand
    {
        get
        {
            return _lazyRebuildCommand.Value;
        }
    }

    public bool IsAvailable
    {
        get
        {
            return _isAvailable;
        }
        set
        {
            _isAvailable = value;
            OnPropertyChanged("IsAvailable");
        }
    }

謝謝你的幫助!

編輯:這是使用模型的過程:我正在使用任務來處理隊列,在隊列中添加要處理的項目:

private static readonly Queue<Project> ProjectsToBuild = new Queue<Project>();
private static bool _isInitialized = false;

public static void AddProjectToBuild(Project projectToAdd)
    {
        projectToAdd.IsAvailable = false;
        ProjectsToBuild.Enqueue(projectToAdd);

        if (!_isInitialized)
        {
            Task.Factory.StartNew(() => ProcessQueue());
            _isInitialized = true;
        }
    }

private static void ProcessQueue()
    {
        while (true)
        {
            if (ProjectsToBuild.Count > 0)
            {
                var project = ProjectsToBuild.Dequeue();
                ProcessCurrentProject(project);                    
            }
            Thread.Sleep(200);
        }
    }

private static void ProcessCurrentProject(Project project)
    {
        Thread.Sleep(3000);
        project.BuildProgress = 50;
        Thread.Sleep(3000);
        project.BuildProgress = 100;
        project.IsPublishable = true;
        project.IsAvailable = true;
        project.RaiseProjectProcessedEvent();
        return;
    }

EDIT2:我使用的RelayCommand:

public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    /// <summary>
    /// Creates a new command that can always execute.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Creates a new command.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <param name="canExecute">The execution status logic.</param>
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }

    #endregion // Constructors

    #region ICommand Members
    [DebuggerStepThrough]
    public bool CanExecute(object parameters)
    {
        //CommandManager.InvalidateRequerySuggested();
        return _canExecute == null ? true : _canExecute(parameters);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameters)
    {
        _execute(parameters);
    }

    #endregion // ICommand Members
}

我認為模板找到正確的狀態存在問題。

排除由於模板而引起的猜測,然后將IsEnable直接綁定到關聯的Can.. status屬性(如果您當前具有這些屬性,並且可能需要添加它們,我就無法理解),但是像這樣:

<DataTemplate x:Key="ProjectTemplate">
<StackPanel Orientation="Horizontal">
   <ProgressBar Value="{Binding BuildProgress}" />
   <TextBox Text="{Binding Label}" IsEnabled="{Binding IsLabelAvailable}" />
   <CheckBox Content="Archive" IsChecked="{Binding ToBeArchived}" IsEnabled="{Binding IsAvailable}" />
   <Button Content="Build" 
           Command="{Binding Path=BuildCommand}" 
           IsEnabled="{Binding CanBuild}"  />
   <Button Content="Rebuild" 
           Command="{Binding Path=RebuildCommand}" 
           IsEnabled="{Binding CanReBuild}" />
   <Button Content="Publish" 
           Command="{Binding Path=PublishCommand}" 
           IsEnabled="{Binding CanPublish}" />
   <TextBlock Text="{Binding Status}" />
   </StackPanel>
</DataTemplate>

然后,確保Can...屬性遵循INotifyProperty更改。

我最終以某種方式解決此問題,任何有此問題的人都可以輕松使用。

在表單的.xaml.cs文件中,訂閱Rendering事件以拍攝“ InvalidateRequerySuggested”,該事件將重新激活按鈕:

    public MainWindow()
    {
        InitializeComponent();
        CompositionTarget.Rendering += OnRendering;
    }

    void OnRendering(object sender, EventArgs e)
    {
        Application.Current.Dispatcher.BeginInvoke(
           DispatcherPriority.Background,
           new Action(CommandManager.InvalidateRequerySuggested));
    }

它是代碼背后的內容,但是因為它僅用於解決GUI問題,所以我認為這是正確的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM