當使用ICommand接口並綁定到通過Command和CommandParameters(或者只是命令)的控件時,通常會意識到按鈕/控件不會自動變爲啓用/禁用(調用CanExecute)當正在使用的值更改。如何使用ICommand輕鬆管理UpdateCanExecute/CanExecute for Multiplex模型
1
A
回答
0
只要有人在這裏感興趣的是一個小回購,迫使ICommand隨時根據需要通過RelayCommand進行更新。這不需要在視圖中做出額外的工作,這使得IMO成爲現實。
中繼命令僅僅是如何容易自動化ICommand接口,並且不意味着是對修復所有溶液的例子。
這裏是RelayCommand
public class RelayCommand : ICommand
{
private readonly RelayCommandBindings relayCommandBindings;
public event EventHandler CanExecuteChanged;
internal RelayCommand(RelayCommandBindings relayCommandBindings)
{
this.relayCommandBindings = relayCommandBindings;
relayCommandBindings.BindingModel.PropertyChanged += (s, e) =>
{
if (relayCommandBindings.BindingProperties.Any(p => p == e.PropertyName))
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
};
}
public bool CanExecute(object parameter) => (relayCommandBindings.CanExecuteChecks?.All(p => p.Invoke(parameter))).GetValueOrDefault();
public void Execute(object parameter) => relayCommandBindings?.Execute?.Invoke(parameter);
}
這裏是RelayCommandBindings
internal class RelayCommandBindings
{
public Action<object> Execute { get; set; }
public IEnumerable<Predicate<object>> CanExecuteChecks { get; set; }
public INotifyPropertyChanged BindingModel { get; set; }
public IEnumerable<string> BindingProperties { get; set; }
}
這裏是視圖模型
public class MultiplexViewModel : INotifyPropertyChanged
{
private const string NoName = "(no name)";
private bool isActive;
private bool isActiveChanging;
private string name;
private readonly MultiPlexModel multiPlexModel;
private readonly SynchronizationContext synchronizationContext;
public MultiplexViewModel()
{
multiPlexModel = new MultiPlexModel();
synchronizationContext = SynchronizationContext.Current;
var bindingProperties = new[]
{
nameof(IsActive),
nameof(IsActiveChanging)
};
var setNewNameBindings = new RelayCommandBindings()
{
Execute = async (obj) => await multiPlexModel.StartMultiplexModelAsync(obj.ToString()),
CanExecuteChecks = new List<Predicate<object>>
{
(obj) => IsValidName(obj?.ToString()),
(obj) => IsActive == false,
(obj) => IsActiveChanging == false
},
BindingModel = this,
BindingProperties = bindingProperties
};
var stopMultiplexBindings = new RelayCommandBindings()
{
Execute = async (obj) => await multiPlexModel.StopMultiplexModelAsync(),
CanExecuteChecks = new List<Predicate<object>>
{
(obj) => IsActive == true,
(obj) => IsActiveChanging == false
},
BindingModel = this,
BindingProperties = bindingProperties
};
SetNewNameCommand = new RelayCommand(setNewNameBindings);
StopMultiplexCommand = new RelayCommand(stopMultiplexBindings);
multiPlexModel.PropertyChanged += (s, e) => GetType().GetProperties().Where(p => p.Name == e.PropertyName).FirstOrDefault()?.SetValue(this, multiPlexModel.GetType().GetProperty(e.PropertyName).GetValue(multiPlexModel));
}
public event PropertyChangedEventHandler PropertyChanged;
public void Notify([CallerMemberName] string propertyName = "") => synchronizationContext.Post((o) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)), null);
public bool IsActive
{
get { return isActive; }
private set
{
isActive = value;
Notify();
}
}
public bool IsActiveChanging
{
get { return isActiveChanging; }
private set
{
isActiveChanging = value;
Notify();
}
}
public string Name
{
get { return string.IsNullOrEmpty(name) ? NoName : name; }
private set
{
name = value;
Notify();
}
}
private bool IsValidName(string name) => (name?.StartsWith("@")).GetValueOrDefault();
public RelayCommand SetNewNameCommand { get; private set; }
public RelayCommand StopMultiplexCommand { get; private set; }
}
這裏是模型
public class MultiPlexModel : INotifyPropertyChanged
{
private bool isActive;
private bool isActiveChanging;
private string name;
public event PropertyChangedEventHandler PropertyChanged;
public void Notify([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public bool IsActive
{
get { return isActive; }
private set
{
isActive = value;
Notify();
}
}
public bool IsActiveChanging
{
get { return isActiveChanging; }
private set
{
isActiveChanging = value;
Notify();
}
}
public string Name
{
get { return name; }
private set
{
name = value;
Notify();
}
}
public async Task StartMultiplexModelAsync(string newName)
{
await Task.Run(async() =>
{
if (IsActiveChanging)
return;
IsActiveChanging = true;
await Task.Delay(2000);
Name = newName;
IsActive = true;
IsActiveChanging = false;
});
}
public async Task StopMultiplexModelAsync()
{
await Task.Run(async() =>
{
if (IsActiveChanging)
return;
IsActiveChanging = true;
await Task.Delay(2000);
Name = string.Empty;
IsActive = false;
IsActiveChanging = false;
});
}
}
這裏是查看
<UserControl.DataContext>
<ViewModels:MultiplexViewModel />
</UserControl.DataContext>
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Auto Relay Command Example"
Margin="12, 40, 12, 12"
FontSize="32"
TextWrapping="Wrap" />
<TextBlock Text="The purpose of this application is to demonstrate a method for automatically activating CanExecute in ICommand. This automatically triggers buttons to become enabled/disabled based on various binding properties at once."
Margin="12"
TextWrapping="Wrap" />
<TextBlock Text="The name of the multiplex can only be set once if it starts with the @ symbol and the multiplex is not active."
Margin="12"
TextWrapping="Wrap" />
<TextBlock Text="The multiplex is started when the name is being properly set. At that time the multiplex cannot be altered... once it is set it cannot be reset until it has been stopped."
Margin="12"
TextWrapping="Wrap" />
<TextBlock Text="There is no code behind, triggers, converters, or other tricks used to make this work. This is purely binding to the commands in the ViewModel. The magic is in the RelayCommand and RelayCommandBindings in the ViewModels namespace."
Margin="12"
TextWrapping="Wrap" />
<TextBox Name="TextBoxName"
Text="{Binding Name, Mode=OneWay}"
Margin="12" />
<Button Content="Set New Name"
Margin="12"
Command="{Binding SetNewNameCommand}"
CommandParameter="{Binding Text, ElementName=TextBoxName}" />
<Button Content="Stop Multiplex"
Margin="12"
Command="{Binding StopMultiplexCommand}" />
<StackPanel Margin="12">
<TextBlock Text="Multiplex Changing" />
<TextBlock Text="{Binding IsActiveChanging}" />
</StackPanel>
<StackPanel Margin="12">
<TextBlock Text="Multiplex Active" />
<TextBlock Text="{Binding IsActive}" />
</StackPanel>
<StackPanel Margin="12">
<TextBlock Text="Multiplex Name" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</StackPanel>
圖片---------
這裏的按鈕來設置新名稱啓用.. 。
個這裏的按鈕,同時激活再次禁用...
這裏名稱設置和停止按鈕被激活......
這裏,一旦停止,視圖又回到了開始。
在這個例子中,你看到不同的屬性設置有直線前進命令,在視圖的方式應該是結合,IMO觀的基調。只是認爲這會有所幫助...
+0
@PeterDuniho如果人們想要使用Git Repo,我可以不在乎。我花時間寫這個例子,所以人們可以看到這個演示工作,只是爲了幫助任何可能被抓到的人嘗試處理在純MVVM架構中修改CanExecute的多個變量。回購只是爲了提供見解/幫助,並且完全沒有用於維護任何其他目的。 –
相關問題
- 1. 如何輕鬆地處理在WPF
- 2. 如何輕鬆打印數字三角形?使用for循環:)
- 3. 如何使用python輕鬆過濾csv?
- 4. 使用Spring JDBC輕鬆處理事務?
- 5. 輕鬆訪問模型領域
- 6. 輕鬆放入模型旋轉
- 7. 輕鬆處理json對象
- 8. 如何在Django項目中輕鬆包含日曆管理模塊
- 9. 如何更輕鬆地使用reCAPTCHA?
- 10. 使用Github輕鬆部署?
- 11. 如何輕鬆地在Eclipse中創建模型/ UML?
- 12. 如何輕鬆測試Yii模型中的文件上傳?
- 13. 使用輕靈還是不輕鬆?
- 14. 我應該如何使用Flask-SQLAlchemy,以便輕鬆添加新模型?
- 15. 如何使用Repository模式讓ORM輕鬆切換?
- 16. 如何更輕鬆地使用IOS模擬器位置?
- 17. 如何輕鬆複製Loopback JS中的模型和相關模型
- 18. 使用servlets輕鬆連接
- 19. 如何輕鬆測試android
- 20. vmware如何輕鬆安裝?
- 21. 如何從JSON update_attributes方法輕鬆
- 22. 如何用awk輕鬆過濾日誌?
- 23. 如何使用ICommand更改模型的屬性?
- 24. 如何輕鬆地使用CodeIgniter進行單元測試?
- 25. 如何處理python導入,使他們可以輕鬆地使用py2和py3?
- 26. 如何輕鬆禁用fancybox幻燈片?
- 27. 如何輕鬆禁用cron作業?
- 28. 如何輕鬆訪問class setter?
- 29. 在expressjs中輕鬆使用助手類
- 30. 如何使用Spring輕鬆使用JSP頁面作爲電子郵件模板?
有堆棧溢出的問題已經討論了確保'CanExecuteChanged'在適當的時候引發的各種策略。如標記重複。另見https://stackoverflow.com/questions/7350845/canexecute-logic-for-delegatecommand,https://stackoverflow.com/questions/6425923/canexecutechanged-event-of-icommand,https://stackoverflow.com/問題/ 30002300 /如何使用的最canexecute法外之ICommand的-ON-wpfhttps://計算器。com/questions/14479303/icommand-canexecute-not-triggering-after-propertychanged,and ... –
https://stackoverflow.com/questions/31078633/wpf-icommand-canexecute-raisecanexecutechanged-or-automatic-handling-via - 二。你的問題不是重寫所有已經寫好的東西,就是堆棧溢出的一個太寬泛的問題(讓我們暫時假設你的問題不僅僅是發佈鏈接到你的網頁的藉口)。如果你確實有一個問題需要幫助,請發佈一個更具體的新問題,其中包括一個好的[mcve],並詳細說明你正在嘗試解決的問題,而你不能。 –
@PeterDuniho上面爲您評論。 –