项目命令无法编辑列表中的其他项目

问题描述 投票:2回答:1

我有一个侧边栏(在C#WPF程序中)应该显示4个“不同”按钮(它们实际上是2种不同的样式,它们都有另一种活动状态样式)。侧边栏包含ItemsControl。我现在设法创建一个列表,其中使用基于枚举值的正确样式(如下所示)。这是一个小问题:我可以这样做,还是应该重写它,如果是这样的话,怎样才能构建这样的东西?关键词或我必须要看的东西对我来说已经足够了。

我现在真正的问题是:我已经将命令绑定到每个按钮,一开始没什么复杂的。该命令现在将其自己的状态设置为NormalActive以进行测试。此列表中的第1项应从LiveActive设置为Live(以便您始终可以看到当前所选项目)。这就是问题:按钮可以设置自己的状态,所以当我点击按钮3时,按钮3的状态从Normal设置为NormalActive。但是没有发生的是从第一个按钮到LiveActive到Active的变化。即使我在更改之前和之后将当前状态输出到控制台,它也会返回LiveActive。如果由于某种原因我不在UI线程中,我也尝试将整个事件调用到调度程序中,它不起作用。因此按钮可以设置自己的状态,但不能设置另一个状态。但我没有得到错误信息或任何东西。此外,还调用属性的setter方法,它不会更改它。可能是什么原因?

PluginListControl:

<Grid DataContext="{x:Static local:PluginListDesignModel.Instance}">
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <ItemsControl ItemsSource="{Binding Items}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:PluginListItemControl />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>
</Grid>

PluginListItemControl:

<UserControl.Resources>
    <DataTemplate x:Key="PluginTile" DataType="{x:Type local:PluginListItemViewModel}">
        <Button Style="{StaticResource PluginTile}" Content="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=ContentControl}}" Command="{Binding DataContext.SetStateCommand, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
    </DataTemplate>

    <DataTemplate x:Key="PluginActiveTile" DataType="{x:Type local:PluginListItemViewModel}">
        <Button Style="{StaticResource PluginActiveTile}" Content="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=ContentControl}}" Command="{Binding DataContext.SetStateCommand, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
    </DataTemplate>

    <DataTemplate x:Key="PluginLiveTile" DataType="{x:Type local:PluginListItemViewModel}">
        <Button Style="{StaticResource PluginLiveTile}" Content="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=ContentControl}}" Command="{Binding DataContext.SetStateCommand, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
    </DataTemplate>

    <DataTemplate x:Key="PluginActiveLiveTile" DataType="{x:Type local:PluginListItemViewModel}">
        <Button Style="{StaticResource PluginActiveLiveTile}" Content="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=ContentControl}}" Command="{Binding DataContext.SetStateCommand, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
    </DataTemplate>
</UserControl.Resources>
<ContentControl d:DataContext="{x:Static local:PluginListItemDesignModel.Instance}">

    <ContentControl.Style>
        <Style TargetType="{x:Type ContentControl}">
            <Setter Property="ContentTemplate" Value="{StaticResource PluginTile}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding State}" Value="0">
                    <Setter Property="ContentTemplate" Value="{StaticResource PluginTile}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding State}" Value="1">
                    <Setter Property="ContentTemplate" Value="{StaticResource PluginActiveTile}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding State}" Value="2">
                    <Setter Property="ContentTemplate" Value="{StaticResource PluginLiveTile}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding State}" Value="3">
                    <Setter Property="ContentTemplate" Value="{StaticResource PluginActiveLiveTile}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>

</ContentControl>

PluginListItemViewModel :(每个列表项的ViewModel)

public class PluginListItemViewModel : BaseViewModel
{
    public string Name { get; set; }
    public PluginTileStates State { get; set; }
    public ICommand SetStateCommand { get; set; }

    #region Constructor

    /// <summary>
    /// Default constructor
    /// </summary>
    public PluginListItemViewModel()
    {
        SetStateCommand = new RelayCommand(() => SetState());
    }

    #endregion

    private void SetState()
    {
        PluginListDesignModel.Instance.Items[0].State = PluginTileStates.Live;
        State = PluginTileStates.NormalActive;
    }
}

重现步骤:

  1. 创建一个新的WPF项目,.NET Framework 4.6.1(Visual Studio 2017)。
  2. 使用以下内容替换MainWindow中的网格:

<Grid DataContext="{x:Static local:ListViewModel.Instance}">
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <ItemsControl ItemsSource="{Binding Items}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:ListItemControl />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>
</Grid>
  1. 添加一个名为ListItemControl的新UserControl并将网格替换为:

<UserControl.Resources>
    <Style x:Key="Tile" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Red" />
    </Style>

    <Style x:Key="ActiveTile" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Green" />
    </Style>

    <DataTemplate x:Key="PluginTile" DataType="{x:Type local:ListItemViewModel}">
        <Button Width="100" Height="60" Style="{StaticResource Tile}" Command="{Binding DataContext.SetStateCommand, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
    </DataTemplate>

    <DataTemplate x:Key="PluginActiveTile" DataType="{x:Type local:ListItemViewModel}">
        <Button Width="100" Height="60" Style="{StaticResource ActiveTile}" Command="{Binding DataContext.SetStateCommand, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
    </DataTemplate>
</UserControl.Resources>
<ContentControl>
    <ContentControl.Style>
        <Style TargetType="{x:Type ContentControl}">
            <Setter Property="ContentTemplate" Value="{StaticResource PluginTile}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding State}" Value="0">
                    <Setter Property="ContentTemplate" Value="{StaticResource PluginTile}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding State}" Value="1">
                    <Setter Property="ContentTemplate" Value="{StaticResource PluginActiveTile}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>
  1. 添加一个名为BaseViewModel的新类,并将class替换为:

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };

    public void OnPropertyChanged(string name)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}
  1. 添加名为ListItemViewModel的新类,并将class替换为:

public enum TileStates
{
    Normal = 0,
    Active = 1
}

public class ListItemViewModel : BaseViewModel
{
    public TileStates State { get; set; }

    public ICommand SetStateCommand { get; set; }

    public ListItemViewModel()
    {
        SetStateCommand = new RelayCommand(() =>
          {
              ListViewModel.Instance.Items[0].State = TileStates.Normal;
              State = TileStates.Active;
          });
    }
}
  1. 添加名为ListViewModel的新类并将class替换为:

public class ListViewModel : BaseViewModel
{
    public static ListViewModel Instance => new ListViewModel();

    public List<ListItemViewModel> Items { get; set; } = new List<ListItemViewModel>
    {
        new ListItemViewModel
        {
            State = TileStates.Active
        },
        new ListItemViewModel
        {
            State = TileStates.Normal
        }
    };
}
  1. 添加一个名为RelayCommand的新类,并将class替换为:

public class RelayCommand : ICommand
{
    private Action mAction;

    public event EventHandler CanExecuteChanged = (sender, e) => { };

    public RelayCommand(Action action)
    {
        mAction = action;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        mAction();
    }
}
  1. 安装NuGet-Packages:“Fody v4.0.2”和“PropertyChanged.Fody v2.6.0”(您可能必须在安装后重新启动Visual Studio

如果您现在按下底部按钮,它应该变为绿色,顶部应该切换为红色。

c# wpf xaml sidebar
1个回答
1
投票

ListViewModel.Instance每次调用时都会返回ListViewModel类的新实例。它应该返回相同的实例:

public static ListViewModel Instance { get; } = new ListViewModel();
© www.soinside.com 2019 - 2024. All rights reserved.