设置 DockPanel 可见性 属性 后,DockPanel 内按钮的数据绑定命令不起作用
Databinding Command for a Button inside a DockPanel not working when a DockPanel Visibility property is set
我正在尝试将 Button Command 属性 绑定到 ViewModel 中的 ICommand 属性(按钮放置在 DockPanel 中)。在我设置 DockPanel 的可见性 属性 之前,它工作正常:
<DockPanel Grid.Row="1">
<Button Content="Read" Command="{Binding ButtonBeginReadCommand}" DockPanel.Dock="Right"/>
<Button Content="Write" Command="{Binding ButtonBeginWriteCommand}" DockPanel.Dock="Left"/>
</DockPanel>
但是在 DockPanel 添加可见性 属性 之后,事情变得奇怪了(现在按钮不可点击,但可见性正常):
<DockPanel Grid.Row="1" Visibility="{Binding IsFilenameCorrect, Converter={StaticResource HiddenIfFalse}}">
<Button Content="Read" Command="{Binding ButtonBeginReadCommand}" DockPanel.Dock="Right"/>
<Button Content="Write" Command="{Binding ButtonBeginWriteCommand}" DockPanel.Dock="Left"/>
</DockPanel>
我也尝试为按钮命令设置 RelativeSource,但没有帮助:
<DockPanel Grid.Row="1" Visibility="{Binding IsFilenameCorrect, Converter={StaticResource HiddenIfFalse}}">
<Button Content="Read" Command="{Binding DataContext.ButtonBeginReadCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" DockPanel.Dock="Right"/>
<Button Content="Write" Command="{Binding DataContext.ButtonBeginWriteCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" DockPanel.Dock="Left"/>
</DockPanel>
DataContext 设置为:
<Window.DataContext>
<viewModel:MainWindowViewModel/>
</Window.DataContext>
有一部分 MainWindowViewModel class。我使用了自定义 AsyncCommand 实现(不记得在哪里找到它):
...
public ICommand ButtonBeginReadCommand { get; private set; }
public MainWindowViewModel() {
...
ButtonBeginReadCommand = new AsyncCommand(async () =>
{
await Task.Delay(300);
Monitor.Enter(_locker);
...
Monitor.Exit(_locker);
});
我该如何解决这个问题?
尝试使用内置 BooleanToVisibilityConverter
。
我正在分享示例代码。您可能必须更改名称空间才能使其正常工作。
XAML:
<Window x:Class="DockPanel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:DockPanel"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<viewModel:VM/>
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<DockPanel Grid.Row="1" Visibility="{Binding IsFilenameCorrect, Converter={StaticResource BooleanToVisibilityConverter}}">
<Button Content="Read" Command="{Binding DataContext.ButtonBeginReadCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" DockPanel.Dock="Right"/>
<Button Content="Write" Command="{Binding DataContext.ButtonBeginWriteCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" DockPanel.Dock="Left"/>
</DockPanel>
</Window>
隐藏代码:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace DockPanel
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class VM
{
public bool IsFilenameCorrect { get; set; }
public ICommand ButtonBeginReadCommand { get; set; }
public ICommand ButtonBeginWriteCommand { get; set; }
private object _locker = new object();
public VM()
{
IsFilenameCorrect = true;
ButtonBeginReadCommand = new AsyncCommand(async () =>
{
await Task.Delay(300);
Monitor.Enter(_locker);
MessageBox.Show("Read");
Monitor.Exit(_locker);
});
ButtonBeginWriteCommand = new AsyncCommand(async () =>
{
await Task.Delay(300);
Monitor.Enter(_locker);
MessageBox.Show("Write");
Monitor.Exit(_locker);
});
}
}
public interface IAsyncCommand : ICommand
{
Task ExecuteAsync(object parameter);
}
public abstract class AsyncCommandBase : IAsyncCommand
{
public abstract bool CanExecute(object parameter);
public abstract Task ExecuteAsync(object parameter);
public async void Execute(object parameter)
{
await ExecuteAsync(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
protected void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
public class AsyncCommand : AsyncCommandBase
{
private readonly Func<Task> _command;
public AsyncCommand(Func<Task> command)
{
_command = command;
}
public override bool CanExecute(object parameter)
{
return true;
}
public override Task ExecuteAsync(object parameter)
{
return _command();
}
}
}
我正在尝试将 Button Command 属性 绑定到 ViewModel 中的 ICommand 属性(按钮放置在 DockPanel 中)。在我设置 DockPanel 的可见性 属性 之前,它工作正常:
<DockPanel Grid.Row="1">
<Button Content="Read" Command="{Binding ButtonBeginReadCommand}" DockPanel.Dock="Right"/>
<Button Content="Write" Command="{Binding ButtonBeginWriteCommand}" DockPanel.Dock="Left"/>
</DockPanel>
但是在 DockPanel 添加可见性 属性 之后,事情变得奇怪了(现在按钮不可点击,但可见性正常):
<DockPanel Grid.Row="1" Visibility="{Binding IsFilenameCorrect, Converter={StaticResource HiddenIfFalse}}">
<Button Content="Read" Command="{Binding ButtonBeginReadCommand}" DockPanel.Dock="Right"/>
<Button Content="Write" Command="{Binding ButtonBeginWriteCommand}" DockPanel.Dock="Left"/>
</DockPanel>
我也尝试为按钮命令设置 RelativeSource,但没有帮助:
<DockPanel Grid.Row="1" Visibility="{Binding IsFilenameCorrect, Converter={StaticResource HiddenIfFalse}}">
<Button Content="Read" Command="{Binding DataContext.ButtonBeginReadCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" DockPanel.Dock="Right"/>
<Button Content="Write" Command="{Binding DataContext.ButtonBeginWriteCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" DockPanel.Dock="Left"/>
</DockPanel>
DataContext 设置为:
<Window.DataContext>
<viewModel:MainWindowViewModel/>
</Window.DataContext>
有一部分 MainWindowViewModel class。我使用了自定义 AsyncCommand 实现(不记得在哪里找到它):
...
public ICommand ButtonBeginReadCommand { get; private set; }
public MainWindowViewModel() {
...
ButtonBeginReadCommand = new AsyncCommand(async () =>
{
await Task.Delay(300);
Monitor.Enter(_locker);
...
Monitor.Exit(_locker);
});
我该如何解决这个问题?
尝试使用内置 BooleanToVisibilityConverter
。
我正在分享示例代码。您可能必须更改名称空间才能使其正常工作。
XAML:
<Window x:Class="DockPanel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:DockPanel"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<viewModel:VM/>
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<DockPanel Grid.Row="1" Visibility="{Binding IsFilenameCorrect, Converter={StaticResource BooleanToVisibilityConverter}}">
<Button Content="Read" Command="{Binding DataContext.ButtonBeginReadCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" DockPanel.Dock="Right"/>
<Button Content="Write" Command="{Binding DataContext.ButtonBeginWriteCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" DockPanel.Dock="Left"/>
</DockPanel>
</Window>
隐藏代码:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace DockPanel
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class VM
{
public bool IsFilenameCorrect { get; set; }
public ICommand ButtonBeginReadCommand { get; set; }
public ICommand ButtonBeginWriteCommand { get; set; }
private object _locker = new object();
public VM()
{
IsFilenameCorrect = true;
ButtonBeginReadCommand = new AsyncCommand(async () =>
{
await Task.Delay(300);
Monitor.Enter(_locker);
MessageBox.Show("Read");
Monitor.Exit(_locker);
});
ButtonBeginWriteCommand = new AsyncCommand(async () =>
{
await Task.Delay(300);
Monitor.Enter(_locker);
MessageBox.Show("Write");
Monitor.Exit(_locker);
});
}
}
public interface IAsyncCommand : ICommand
{
Task ExecuteAsync(object parameter);
}
public abstract class AsyncCommandBase : IAsyncCommand
{
public abstract bool CanExecute(object parameter);
public abstract Task ExecuteAsync(object parameter);
public async void Execute(object parameter)
{
await ExecuteAsync(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
protected void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
public class AsyncCommand : AsyncCommandBase
{
private readonly Func<Task> _command;
public AsyncCommand(Func<Task> command)
{
_command = command;
}
public override bool CanExecute(object parameter)
{
return true;
}
public override Task ExecuteAsync(object parameter)
{
return _command();
}
}
}