[英]Button databinding in list doesn't behave correctly
我是MVVM的新手,但有一個奇怪的行為,但未能成功解決:我通過列表顯示了一些按鈕(和其他元素):
即使其他元素對數據綁定的行為正確(在對象更改狀態時更新),按鈕也只能正確停用,而不會相對於命令狀態重新激活:我必須單擊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.