XAML WPF切换组合框项目文本颜色MVVM ReactiveUI

x8goxv8g  于 2022-12-07  发布在  React
关注(0)|答案(3)|浏览(200)

好吧,所以这绝对是一个新手问题,不幸的是无法计算/找到答案。
实际上是将一个对象列表绑定到一个Combobox,当对象的Disabled属性设置为true时,我希望Combobox项的文本颜色设置为灰色。
这是我目前所掌握的情况:

组合框项数据类型

public class ListItem
{
    public ListItem(string text)
    {
        Text = text;
    }

    public string Text { get; set; }
    public bool Disabled { get; set; }
}

查看模型设置

public class MainPageViewModel : ReactiveObject
{
    // In ReactiveUI, this is the syntax to declare a read-write property
    // that will notify Observers, as well as WPF, that a property has 
    // changed. If we declared this as a normal property, we couldn't tell 
    // when it has changed!
    private ListItem _selectedItem;
    public ListItem SelectedItem
    {
        get => _selectedItem;
        set => this.RaiseAndSetIfChanged(ref _selectedItem, value);
    }

    public List<ListItem> Items { get; set; }

    public MainPageViewModel()
    {
        Items = new List<ListItem>
        {
            new ListItem ("A Cat"),
            new ListItem ("A Dog"),
            new ListItem ("A Mouse"),
            new ListItem ("A Frog") { Disabled = true }
        };
    }
}

React式UI绑定

public MainPage()
{
  InitializeComponent();

  ViewModel = new MainPageViewModel();
  
  this.WhenActivated(d =>
  {
    this.OneWayBind(ViewModel, vm => vm.Items, v => v.MyComboBox.ItemsSource)
                    .DisposeWith(d);

    this.Bind(ViewModel, vm => vm.SelectedItem, v => v.MyComboBox.SelectedItem)
                    .DisposeWith(d);

  });
}

XAML标记

<ComboBox
 Name="MyComboBox"
 Margin="0,0,0,20"
 Foreground="black">
   <ComboBox.ItemTemplate>
     <DataTemplate>
       <TextBlock Text="{Binding}" />
     </DataTemplate>
   </ComboBox.ItemTemplate>

   <ComboBox.ItemContainerStyle>
     <Style TargetType="ComboBoxItem">
       <Style.Triggers>
         <DataTrigger Binding="{Binding Path=Disabled}" Value="True">
           <Setter Property="Foreground" Value="Gray" />
         </DataTrigger>
       </Style.Triggers>
     </Style>
    </ComboBox.ItemContainerStyle>

 </ComboBox>

如果您需要更多信息,请告诉我。
解决方法:看起来在以后我需要在安装之前测试示例代码-我们的实际代码将Disabled属性设置为readonly,这肯定会扰乱WPF绑定。将其更改为公共设置,并解决了看不到它变灰的第一个问题!看起来盯着一个问题看了这么长时间会让你失明,这真的很简单。至于灰色的选定项目,我会尝试一下,看看。

sauutmhj

sauutmhj1#

下拉列表中的最后一项的文本已经变灰,所以我假设您正在询问有关选定项的问题。ComboBox为选定项和下拉列表中的项使用单独的数据模板。您可以使用DataTemplateSelector来设置这两者。

public class ComboBoxTemplateSelector : DataTemplateSelector
{
    public DataTemplate SelectedItemTemplate { get; set; }
    public DataTemplate DropdownItemsTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var itemToCheck = container;

        // Search up the visual tree, stopping at either a ComboBox or a ComboBoxItem (or null).
        // This will determine which template to use.
        while (itemToCheck is not null and not ComboBox and not ComboBoxItem)
            itemToCheck = VisualTreeHelper.GetParent(itemToCheck);

        // If you stopped at a ComboBoxItem, you're in the dropdown.
        return itemToCheck is ComboBoxItem ? DropdownItemsTemplate : SelectedItemTemplate;
    }
}
XAML标记
<StackPanel>
    <StackPanel.Resources>
        <Style x:Key="GrayedOutText" TargetType="TextBlock">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Disabled}" Value="True">
                    <Setter Property="Foreground" Value="Gray" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
        <local:ComboBoxTemplateSelector x:Key="ComboBoxTemplateSelector">
            <local:ComboBoxTemplateSelector.SelectedItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Text}" Style="{StaticResource GrayedOutText}" />
                </DataTemplate>
            </local:ComboBoxTemplateSelector.SelectedItemTemplate>
            <local:ComboBoxTemplateSelector.DropdownItemsTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Text}" Style="{StaticResource GrayedOutText}" />
                </DataTemplate>
            </local:ComboBoxTemplateSelector.DropdownItemsTemplate>
        </local:ComboBoxTemplateSelector>
    </StackPanel.Resources>
    <ComboBox
         Name="MyComboBox"
         Margin="0,0,0,20"
         ItemTemplateSelector="{StaticResource ComboBoxTemplateSelector}">
    </ComboBox>
</StackPanel>

我们在DataTemplate定义中有一些重复,但在生产代码中这些定义往往会变得不同。

资源
qxsslcnc

qxsslcnc2#

我假设你的问题是ComboBoxItem在应用程序运行后不会变灰。
我不熟悉ReactiveUI,但由于我在您的代码中发现了一个问题,所以我在您的代码的CommunityToolkit.Mvvm版本中进行了尝试,并验证了我的理论。
最后,您需要将INotifyPropertyChangedReactiveUI版本实现到Disabled属性。
如果你有兴趣,我可以发布CommunityToolkit.mvvm版的这段代码。

wyyhbhjk

wyyhbhjk3#

下面是一个在我的测试中行之有效的方法:
组合框项数据类型:

//-- Unchanged
public class ListItem
{
    public ListItem( string text )
    {
        Text = text;
    }

    public string Text { get; set; }

    public bool Disabled { get; set; }
}

视图模型设置:

public class MainPageViewModel : INotifyPropertyChanged
{
    private ListItem? _selectedItem;

    public event PropertyChangedEventHandler? PropertyChanged;

    public ListItem? SelectedItem
    {
        get => _selectedItem;
        set
        {
            //-- I didn't had the "RaiseAndSetIfChanged" method, so I just implemented the functionality manually
            if( value != _selectedItem )
            {
                //-- Update the value ...
                _selectedItem = value;

                //-- ... AND inform everyone (who is interested) about the change
                this.PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( nameof( this.SelectedItem ) ) );
            }
        }
    }

    //-- Use always an ObservableCollection when you want to achieve reactivity
    public ObservableCollection<ListItem> Items 
    { get; } = new ObservableCollection<ListItem>();

    public MainPageViewModel()
    {
        //-- Add some test data
        this.Items.Add( new ListItem( "A Cat" ) );
        this.Items.Add( new ListItem( "A Dog" ) );
        this.Items.Add( new ListItem( "A Mouse" ) );
        this.Items.Add( new ListItem( "A Frog" ) { Disabled = true } );

        //-- Just select the first item
        this.SelectedItem = this.Items[0];
    }
}

首页:

public MainPage()
    {
        //-- Define the DataContext BEFORE the UI will be initialized ;)
        this.DataContext = new MainPageViewModel();

        InitializeComponent();

        //-- Never saw such code before -> just don't do that ;)

        //this.WhenActivated( d =>
        //{
        //    this.OneWayBind( ViewModel, vm => vm.Items, v => v.MyComboBox.ItemsSource )
        //                    .DisposeWith( d );

        //    this.Bind( ViewModel, vm => vm.SelectedItem, v => v.MyComboBox.SelectedItem )
        //                    .DisposeWith( d );

        //} );
    }

XAML标记:

<DockPanel>

    <ComboBox
        DockPanel.Dock="Top"
        Name="MyComboBox"
        Margin="0,0,0,20"
        Foreground="black"
        ItemsSource="{Binding Items}"
        SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Text}" />
            </DataTemplate>
        </ComboBox.ItemTemplate>

        <ComboBox.ItemContainerStyle>
            <Style TargetType="ComboBoxItem">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=Disabled}" Value="True">
                        <Setter Property="Foreground" Value="Gray" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ComboBox.ItemContainerStyle>

    </ComboBox>
    
    <!-- Details View -->
    <StackPanel>
        
        <!-- name -->
        <StackPanel Orientation="Horizontal">

            <Label Content="Item Name" />
            <TextBox Text="{Binding SelectedItem.Text}" />

        </StackPanel>

        <!-- disabled flag -->
        <StackPanel Orientation="Horizontal">

            <Label Content="IsDisabled" />
            <CheckBox IsChecked="{Binding SelectedItem.Disabled}" />
        </StackPanel>
    </StackPanel>   
</DockPanel>

希望这能满足你的要求。玩得开心:)

相关问题