我有一個帶有 DataGrid 的 (WPF) Catel DataWindow,其中 SelectedItem 屬性系結到 VM 屬性,并且有兩個縮進按鈕以在所選資料網格項上啟動不同的 Catel TaskCommand。
請注意,CommandParameters 以不同的方式系結到看起來 -但實際上不是- 相同的值:
<catel:DataWindow x:Class="CatelWPFApplication1.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://schemas.catelproject.com"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:CatelWPFApplication1.ViewModels"
mc:Ignorable="d"
ShowInTaskbar="True"
ResizeMode="NoResize"
SizeToContent="WidthAndHeight"
WindowStartupLocation="Manual"
d:DataContext="{d:DesignInstance Type=viewModels:MainWindowViewModel, IsDesignTimeCreatable=True}"
>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" Margin="0,6">
<Button Command="{Binding ViaVmCommand}"
CommandParameter="{Binding SelectedPerson, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Content="Binding via VM" />
<Button Command="{Binding ViaElementNameCommand}"
CommandParameter="{Binding SelectedItem, ElementName=PersonDataGrid, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Content="Binding via ElementName"
x:Name="ViaElementButton"/>
</StackPanel>
<DataGrid x:Name="PersonDataGrid"
ItemsSource="{Binding PersonList}"
SelectedItem="{Binding SelectedPerson, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
AutoGenerateColumns="True" />
</StackPanel>
</catel:DataWindow>
為了完整起見,下面給出了 VM 代碼。
當第一次顯示視窗時,沒有選擇資料網格行,正如預期的那樣,兩個按鈕都被禁用。如果第一個資料網格行被選中(通過單擊滑鼠),則只有一個系結到 VM 的 SelectedPerson 屬性的按鈕被啟用,而令我驚訝的是另一個按鈕保持禁用狀態。在選擇不同的專案時,兩個按鈕都被啟用,并且在 Crtl-Clicking 取消選擇選定的行時,VM 系結按鈕被禁用,而通過 ElementName 機制的一個系結不會。
使用除錯器斷點,我證明了在視窗初始化和每個專案選擇更改時都呼叫了 CanExecute 函式。然而,通過 ElementName 參考的 Button 系結引數是一鍵式的。
如果我在其中一個命令中更改 VM SelectedPerson 屬性,兩個按鈕都會按預期更新,它們的 CanExecute 處理程式會獲得正確的專案值。
我發現系結到 VM 屬性還不錯,因為它在業務邏輯的其他地方很有用,但我喜歡了解為什么這兩種方法的行為如此不同。
'ElementName' 系結是怎么回事,為什么一鍵落后?
最后,這是VM
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Catel.Data;
using Catel.MVVM;
using CatelWPFApplication1.Models;
namespace CatelWPFApplication1.ViewModels
{
/// <summary>
/// MainWindow view model.
/// </summary>
public class MainWindowViewModel : ViewModelBase
{
#region Fields
#endregion
#region Constructors
public MainWindowViewModel()
{
ViaVmCommand = new TaskCommand<Person>(OnViaVmCommandExecute, OnViaVmCommandCanExecute);
ViaElementNameCommand = new TaskCommand<Person>(OnViaElementNameCommandExecute, OnViaElementNameCommandCanExecute);
PersonList = new List<Person>();
PersonList.Add(new Person(){FirstName = "Albert", LastName = "Abraham"});
PersonList.Add(new Person(){FirstName = "Betty", LastName = "Baboa"});
PersonList.Add(new Person(){FirstName = "Cherry", LastName="Cesar"});
}
#endregion
#region Properties
/// <summary>
/// Gets the title of the view model.
/// </summary>
/// <value>The title.</value>
public override string Title { get { return "View model title"; } }
public List<Person> PersonList { get; }
// classic Catel property, avoiding any magic with Fody weavers
public Person SelectedPerson
{
get { return GetValue<Person>(SelectedPersonProperty); }
set
{
SetValue(SelectedPersonProperty, value);
}
}
public static readonly PropertyData SelectedPersonProperty = RegisterProperty(nameof(SelectedPerson), typeof(Person), null);
#endregion
#region Commands
public TaskCommand<Person> ViaElementNameCommand { get; }
private bool OnViaElementNameCommandCanExecute(Person person)
{
return person is not null;
}
private async Task OnViaElementNameCommandExecute(Person person)
{
SelectedPerson = null;
}
public TaskCommand<Person> ViaVmCommand { get; }
private bool OnViaVmCommandCanExecute(Person person)
{
return person is not null;
}
private async Task OnViaVmCommandExecute(Person person)
{
SelectedPerson = PersonList.FirstOrDefault();
}
#endregion
}
}
uj5u.com熱心網友回復:
我認為這是由命令得到(重新)評估的那一刻引起的。
您可能將該InvalidateCommandsOnPropertyChange屬性設定為true(默認值)。有關更多資訊,請參閱https://github.com/catel/catel/blob/develop/src/Catel.MVVM/MVVM/ViewModels/ViewModelBase.cs#L1016
在這個階段,系結可能還沒有機會更新自己,因此正在發送以前的版本。
此問題的解決方法可能是使用 VM 內的調度程式服務自己重新評估命令:
在演員中:
private readonly IDispatcherService _dispatcherService;
public MainWindowViewModel(IDispatcherService dispatcherService)
{
Argument.IsNotNull(() => dispatcherService);
_dispatcherService = dispatcherService;
}
覆寫 OnPropertyChanged:
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
// Don't alter current behavior by calling base
base.OnPropertyChanged(e);
// Dispatcher so the bindings get a chance to update
_dispatcherService.BeginInvoke(await () =>
{
await Task.Delay(10);
ViewModelCommandManager.InvalidateCommands();
});
}
免責宣告:這是沒有編輯器的代碼,但希望它能讓你知道它應該做什么
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/313965.html
上一篇:如何使用DataTrigger更改ItemsControl中的ItemsPanel?
下一篇:DynamicResource更改FontSize和TextColor然后保存在App.Current.Resources
