【问题标题】:Button unclickable upon rendering of Window渲染窗口时按钮不可点击
【发布时间】:2016-10-05 16:02:02
【问题描述】:

我有一个 WPF 应用程序,它不允许我单击按钮,直到过了一点时间,但这种行为是随机的,它只在某些时候发生。大多数情况下,窗口呈现,我可以立即单击所述按钮。

主窗口:

    <views:StatusBox DockPanel.Dock="Left" Visibility="{Binding Editing, Converter={StaticResource BoolToVisibleConverter}}" />
</DockPanel>

用户控制:

<StackPanel Orientation="Horizontal">
    <!--Read Button-->
    <Button Content="Read "   x:Name="ReadBtn"     Command="{Binding ReadCMD}"    Padding="10,5" Margin= "10,0" IsEnabled="{Binding ReadEnabled}" />

    <!--Save Button-->
    <Button Content="Save "   x:Name="SaveBtn"     Command="{Binding SaveCMD}"    Padding="10,5" Margin= "10,0" IsEnabled="{Binding SaveEnabled}" 
            Background="{StaticResource {x:Static SystemColors.ControlLightBrushKey}}">
        <Button.Style>
            <Style TargetType="Button">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsSaveNeeded}" Value="Yes">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard x:Name="FlashBackground">
                                <Storyboard BeginTime="00:00:00" RepeatBehavior="Forever" >
                                    <ColorAnimation  Storyboard.TargetProperty="Background.Color" Duration="00:00:00.25" AutoReverse="True" To="Red" />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>

                        <DataTrigger.ExitActions>
                            <StopStoryboard BeginStoryboardName="FlashBackground" />
                        </DataTrigger.ExitActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>

    <!--Load Button-->
    <Button Content="Load "   x:Name="LoadBtn"     Command="{Binding LoadCMD}"    Padding="10,5" Margin= "10,0" IsEnabled="{Binding LoadEnabled}" />

    <!--Print Button-->
    <Button Content="Print"   x:Name="PrintBtn"    Command="{Binding PrintCMD}"   Padding="10,5" Margin= "10,0" IsEnabled="{Binding PrintEnabled}" />

    <!--Exit Button-->
    <Button Content="Exit"    x:Name="ExitBtn"     Command="{Binding ExitCMD}"    Padding="10,5" Margin= "10,0" />
</StackPanel>

查看模型

private bool _tab1_Selected;
    public bool tab1_Selected
    {
        get
        {
            return _tab1_Selected;
        }
        set
        {
            _tab1_Selected = value;

            if (value)
            {
                CommMode = (byte)PacketType.tab1_DUMP;

                if (tab1needsSaving)
                {
                    IsSaveNeeded = SaveNeeded.Yes;
                }
                else
                {
                    IsSaveNeeded = SaveNeeded.No;
                }
            }

            NotifyPropertyChanged("tab1_Selected");
            NotifyPropertyChanged("SaveEnabled");
            NotifyPropertyChanged("ProgramEnabled");
            NotifyPropertyChanged("Editing");
        }
    }


    private bool _tab2_Selected;
    public bool tab2_Selected
    {
        get
        {
            return _tab2_Selected;
        }
        set
        {
            _tab2_Selected = value;

            if (value)
            {
                CommMode = (byte)PacketType.tab2_DUMP;

                if (tab2needsSaving)
                {
                    IsSaveNeeded = SaveNeeded.Yes;
                }
                else
                {
                    IsSaveNeeded = SaveNeeded.No;
                }
            }

            NotifyPropertyChanged("tab2_Selected");
            NotifyPropertyChanged("SaveEnabled");
            NotifyPropertyChanged("ProgramEnabled");
            NotifyPropertyChanged("Editing");
        }
    }


public bool Editing
    {
        get
        {
            return tab2_Selected || tab1_Selected;
        }
    }

 private bool _saveEnabled;
    public bool SaveEnabled
    {
        get
        {
            //return _saveEnabled;
            return ((tab1_Selected && tab1Data != null && tab1Data.Count > 0) || (tab2_Selected && tab2Data != null && tab2Data.Count > 0) && _saveEnabled);
        }
        set
        {
            _saveEnabled = value;
            NotifyPropertyChanged("SaveEnabled");
        }
    }

 private bool _programEnabled;
    public bool ProgramEnabled
    {
        get
        {
            //return _saveEnabled;
            return ((tab1_Selected && tab1Data != null && tab1Data.Count > 0) || (tab2_Selected && tab2Data != null && tab2Data.Count > 0) && _programEnabled);
        }
        set
        {
            _programEnabled = value;
            NotifyPropertyChanged("ProgramEnabled");
        }
    }

命令:

    public ICommand ReadCMD     { get; set; }
    public ICommand SaveCMD     { get; set; }
    public ICommand LoadCMD     { get; set; }
    public ICommand ProgramCMD  { get; set; }
    public ICommand PrintCMD    { get; set; }
    public ICommand ExitCMD     { get; set; }

    // In MainVM constructor
    ReadCMD = new RelayCommand(ReadSettings);
    SaveCMD = new RelayCommand(SaveSettings);
    LoadCMD = new RelayCommand(LoadSettings);
    ProgramCMD = new RelayCommand(ProgramSettings);
    PrintCMD = new RelayCommand(PrintSettings);
    ExitCMD = new RelayCommand(ExitProgram);

中继命令类:

 public class RelayCommand : ICommand
{
    private Action<object> execute;

    private Predicate<object> canExecute;

    private event EventHandler CanExecuteChangedInternal;

    public RelayCommand(Action<object> execute)
        : this(execute, DefaultCanExecute)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        if (canExecute == null)
        {
            throw new ArgumentNullException("canExecute");
        }

        this.execute = execute;
        this.canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
            this.CanExecuteChangedInternal += value;
        }

        remove
        {
            CommandManager.RequerySuggested -= value;
            this.CanExecuteChangedInternal -= value;
        }
    }

    public bool CanExecute(object parameter)
    {
        return this.canExecute != null && this.canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        this.execute(parameter);
    }

    public void OnCanExecuteChanged()
    {
        EventHandler handler = this.CanExecuteChangedInternal;
        if (handler != null)
        {
            //DispatcherHelper.BeginInvokeOnUIThread(() => handler.Invoke(this, EventArgs.Empty));
            handler.Invoke(this, EventArgs.Empty);
        }
    }

    public void Destroy()
    {
        this.canExecute = _ => false;
        this.execute = _ => { return; };
    }

    private static bool DefaultCanExecute(object parameter)
    {
        return true;
    }
}

更新:

我从DockPanel 切换到StackPanel 并将宽度设置为StatusBox,而不是允许LastChildFill 调整状态字段,这解决了我的问题。即使我在 StatusBox 周围设置了一个边框以查看它的渲染位置,它仍然给我带来了问题。

【问题讨论】:

  • 请解释SaveEnabled等的属性或发布更多代码。如果缺少一半,很难在绑定中找到错误。
  • @Ihildebrandt - 我已经为你添加了 SaveEnabled 和 ProgramEnabled 属性。
  • 是不是有SaveEnabled的按钮有问题?顺便说一句,您的 ICommand 实现如何?
  • 我添加了 ICommand 信息。是“阅读”按钮给了我这个问题。程序首次启动时,保存按钮被禁用。

标签: .net wpf button rendering


【解决方案1】:

您不需要显式绑定到 SaveEnabled 属性,以根据是否可以执行命令来禁用/启用按钮。 只需在 RelayCommand 的谓词中包含 CanExecute 逻辑,如果属性发生更改,请在命令上调用 OnCanExecuteChanged 以启用按钮。

编辑

像这样的

private ICommand saveCMD;

public ICommand SaveCMD     
{ 
   get
   {
      if(this.saveCMD == null)
      {
         this.saveCMD = new RelayCommand(this.SaveSettings, this.CanSaveSettings)
      }

      return saveCMD;
   }
}

public bool CanSaveSettings()
{
     return ((tab1_Selected && tab1Data != null && tab1Data.Count > 0) || (tab2_Selected && tab2Data != null && tab2Data.Count > 0) && _saveEnabled);
}

然后在您看来,您应该能够使用它并且它应该可以工作:

<Button Content="Save" x:Name="SaveBtn" Command="{Binding SaveCMD}" Padding="10,5" Margin= "10,0"/> 

【讨论】:

  • @Ihildebrandt,你能举个例子吗?我之前在其他项目上做过此操作,无法让 UI 刷新按钮,因此不得不切换到调用 Property Changed 事件的属性。因此,我为什么要这样写。
  • 编辑了我的主要帖子。请检查这是否能解决您的问题。
  • 我试过这个,但没有帮助。程序启动后每隔一段时间我仍然无法立即点击阅读按钮。
  • 可能读取命令的逻辑耗时太长?尝试设置断点并找出命令的谓词何时第一次调用与第一次为真。
猜你喜欢
  • 1970-01-01
  • 2021-11-28
  • 2018-04-23
  • 1970-01-01
  • 2021-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多