【问题标题】:Databinding Command for a Button inside a DockPanel not working when a DockPanel Visibility property is set设置 DockPanel Visibility 属性时,DockPanel 内的按钮的数据绑定命令不起作用
【发布时间】:2015-05-02 01:37:19
【问题描述】:

我正在尝试将 Button Command 属性绑定到 ViewModel 中的 ICommand 属性(按钮放置在 DockPanel 中)。在我设置 DockPanel 的 Visibility 属性之前它工作正常:

<DockPanel  Grid.Row="1">
     <Button Content="Read" Command="{Binding ButtonBeginReadCommand}" DockPanel.Dock="Right"/>
     <Button Content="Write" Command="{Binding ButtonBeginWriteCommand}" DockPanel.Dock="Left"/>
</DockPanel>

但是在将 Visibility 属性添加到 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 类的一部分。我使用了一个自定义的 AsyncCommand 实现(不记得我在哪里找到的):

...
public ICommand ButtonBeginReadCommand { get; private set; }
public MainWindowViewModel() {
...
ButtonBeginReadCommand = new AsyncCommand(async () =>
        {

            await Task.Delay(300);
            Monitor.Enter(_locker);
            ...
            Monitor.Exit(_locker);
        });

我该如何解决这个问题?

【问题讨论】:

  • 设置Visiblity 属性不会影响您的绑定。您共享的代码对我来说很好。你能分享更多代码吗?
  • 对不起,我使用了 CustomBoolToVis 转换器,然后尝试设置 Visibility="Visible" - 效果相同。更新了问题,添加了 MainWindowViewModel 的一部分。
  • 不确定为什么要初始化ButtonBeginRead 属性?您应该初始化 ButtonBeginReadCommand 属性。检查我的示例代码。
  • ButtonBeginRead
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。

标签: c# wpf data-binding


【解决方案1】:

尝试使用内置的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();
        }
    }
}

【讨论】:

  • 对我帮助很大,谢谢。实际上,问题出在自定义 BooleanToVisibilityConverter link 中。我不知道为什么它破坏了绑定过程。您能否在答案中指出这个问题,然后我编辑我的问题并将答案标记为已接受?也许它会帮助某人。
  • 很高兴能为您提供帮助。我已经改变了答案。
猜你喜欢
  • 2013-07-07
  • 1970-01-01
  • 2018-07-31
  • 1970-01-01
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多