簡體   English   中英

MaterialDesignInXaml ComboBox - 清除按鈕問題

[英]MaterialDesignInXaml ComboBox - Clear button issue

我正在使用 MaterialDesignInXaml 和 ReactiveUI 構建 WPF 應用程序。 我有以下 XAML 代碼:

<ItemsControl ItemsSource="{Binding Filters}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type local:FilterViewModel}">
            <ComboBox
                Margin="6,0,6,12"
                materialDesign:HintAssist.HelperText="{Binding Name}"
                materialDesign:HintAssist.Hint="{Binding Name}"
                materialDesign:TextFieldAssist.HasClearButton="True" /// <--- clear button doesn't work!
                ItemsSource="{Binding Options}"
                SelectedItem="{Binding SelectedOption}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

以及對應的 ViewModel:

public class MainWindowViewModel : ReactiveObject
{
    public List<FilterViewModel> Filters { get; set; } = new();

    public MainWindowViewModel()
    {
        Filters = Enumerable.Range(1, 3).Select(x => new FilterViewModel()
        {
            Name = $"Filter {x}",
            Options = new ObservableCollection<string>(Enumerable.Range(1, 5).Select(y => y.ToString()))
        }).ToList();
    }
}

public class FilterViewModel : ReactiveObject
{
    public ObservableCollection<string> Options { get; set; } = new();

    public string Name
    {
        get => _name;
        set => this.RaiseAndSetIfChanged(ref _name, value);
    }

    public string SelectedOption
    {
        get => _selectedOption;
        set => this.RaiseAndSetIfChanged(ref _selectedOption, value);
    }

    private string _selectedOption;
    private string _name;
}

這給了我很好的三個組合框:

三個帶有提示文本的 ComboBox 水平對齊,中間的 ComboBox 顯示“2”,右側有一個“X”清除按鈕。

問題是ComboBox清除按鈕在單擊時無效。 它根本不做任何事情,沒有錯誤,什么都沒有。 我在這里錯過了什么嗎? 為什么它不起作用?

這是在 GitHub 上跟蹤的 MaterialDesign 中的一個錯誤:

問題出在ClearText.OnClearCommand方法中,該方法是為綁定到清除按鈕的ClearCommand執行的。 假設事件的SourceComboBox ,但它是按鈕本身,因此該方法不會清除任何內容。

不幸的是, ClearCommand在控制模板中是硬連線的,請參見此處

<Button
   x:Name="PART_ClearButton"
   Grid.Column="2"
   Height="Auto"
   Padding="2,0,0,0"
   Command="{x:Static internal:ClearText.ClearCommand}"
   Focusable="False"
   Style="{StaticResource MaterialDesignToolButton}">

因此,清除命令的修復需要復制ClearText類、修復錯誤、復制ComboBox的所有相關樣式並在控件模板中使用命令的本地修復版本。


獎勵回合:您可以在代碼中解決這個問題,但這或多或少是一個骯臟的修復。 您可以在加載ComboBox時搜索清除按鈕並重新分配命令的固定版本。

我使用Microsoft.Xaml.Behaviors.Wpf NuGet 包將此修復封裝到一個可重用的組件中,該組件可以輕松集成,但您也可以改用代碼隱藏。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using MaterialDesignThemes.Wpf.Internal;
using Microsoft.Xaml.Behaviors;

namespace SignumsAwesomeApp
{
   public class MaterialDesignComboBoxClearButtonFixBehavior: Behavior<ComboBox>
   {
      private static readonly RoutedCommand ClearCommand = new RoutedCommand();

      protected override void OnAttached()
      {
         base.OnAttached();
         AssociatedObject.Loaded += OnLoaded;
      }

      protected override void OnDetaching()
      {
         base.OnDetaching();
         AssociatedObject.Loaded -= OnLoaded;
      }

      private void OnLoaded(object sender, RoutedEventArgs e)
      {
         if (!ClearText.GetHandlesClearCommand(AssociatedObject))
            return;

         AssociatedObject.CommandBindings.Add(new CommandBinding(ClearCommand, OnClearCommand));
         FindChild<Button>(AssociatedObject, "PART_ClearButton").Command = ClearCommand;
      }

      private void OnClearCommand(object sender, ExecutedRoutedEventArgs e)
      {
         AssociatedObject.SetCurrentValue(ComboBox.TextProperty, null);
         AssociatedObject.SetCurrentValue(Selector.SelectedItemProperty, null);
      }

      private static T FindChild<T>(DependencyObject parent, string childName)
         where T : DependencyObject
      {
         if (parent == null)
            return null;

         T foundChild = null;

         var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
         for (var i = 0; i < childrenCount; i++)
         {
            var child = VisualTreeHelper.GetChild(parent, i);
            if (!(child is T childType))
            {
               foundChild = FindChild<T>(child, childName);

               if (foundChild != null) break;
            }
            else if (!string.IsNullOrEmpty(childName))
            {
               if (childType is FrameworkElement frameworkElement && frameworkElement.Name == childName)
               {
                  foundChild = childType;
                  break;
               }
            }
            else
            {
               foundChild = childType;
               break;
            }
         }

         return foundChild;
      }
   }
}

FindChild方法來自@CrimsonX對這個問題的回答:

您必須將行為添加到 XAML 中的ComboBox中,如下所示:

<ComboBox ...>
   <b:Interaction.Behaviors>
      <local:MaterialDesignComboBoxClearButtonFixBehavior/>
   </b:Interaction.Behaviors>
</ComboBox>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM