C# Item命令无法编辑列表中的其他项

C# Item命令无法编辑列表中的其他项,c#,wpf,xaml,sidebar,C#,Wpf,Xaml,Sidebar,我有一个侧边栏(在C#WPF程序中),应该显示4个“不同”的按钮(它们实际上是两种不同的样式,它们都有另一种用于活动状态的样式)。侧栏由ItemsControl组成。我现在已经创建了一个列表,其中基于枚举值使用了正确的样式(如下所示)。这里有一个小问题:我可以这样做吗,或者我应该重写它,如果是这样的话,这样的东西是如何构建的?关键词或者我必须看的东西对我来说已经足够了 我现在真正的问题是:我已经为每个按钮绑定了一个命令,一开始并不复杂。该命令现在将其自身状态设置为NormalActive以进行测

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

我现在真正的问题是:我已经为每个按钮绑定了一个命令,一开始并不复杂。该命令现在将其自身状态设置为NormalActive以进行测试。此列表中的第一项应该从LiveActive设置为Live(以便您始终可以看到您所知道的当前选定项)。问题是:按钮可以设置自己的状态,所以当我点击按钮3时,按钮3的状态从正常设置为正常激活。但没有发生的是从第一个按钮从LiveActive更改为Active。即使我在更改之前和之后将当前状态输出到控制台,它也会同时返回LiveActive。我还尝试将整个事件调用到dispatcher中,如果出于某种原因我不在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>
<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>
  • 添加名为ListItemViewModel的新类,并将该类替换为:

  • 添加名为ListViewModel的新类,并将该类替换为:

  • 安装NuGet软件包:“Fody v4.0.2”和“PropertyChanged.Fody v2.6.0”(安装后可能需要重新启动Visual Studio)

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

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

    public static ListViewModel Instance { get; } = new ListViewModel();
    

    如何调试setter?它是从代码以外的其他地方调用的吗?我添加了一个私有变量。如下所示:private-plugintelestates-mState;public-plugintelestates-State{get=>mState;set{Console.WriteLine($”设置为:{value}”);mState=value;}我当然把它设置为State=PluginTileStates.Live;那么你怎么知道它没有设置为
    PluginTileStates.Live
    ?或者你的意思是你在UI中看不到变化?你能提供一个吗?好的,一方面样式应该改变,因为值改变了(至少从理论上讲,这是我第一次这么做,可能是因为数据模板的缘故我错过了一些东西).另一方面,如上所述,我有当前状态的输出给我,无论是在更改为PluginTileStates之前还是之后。Live。至于MCVE:我当然可以做一个小项目,但我如何将它放在这里?只需将它上传到某个地方并将链接发布到这里?所以我无法将其缩小。现在我将它作为Ste添加到问题中哦,我的上帝,这是一个致命的,同时也是一个简单的错误…这就是谜题的答案,非常感谢!
    <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>
    
    <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>
    
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
    
        public void OnPropertyChanged(string name)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
    
    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;
              });
        }
    }
    
    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
            }
        };
    }
    
    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();
        }
    }
    
    public static ListViewModel Instance { get; } = new ListViewModel();