我有一个侧边栏(在C#WPF程序中),应显示4个“不同”按钮(它们实际上是2种不同的样式,对于活动状态它们都有另一种样式)。侧边栏包含一个ItemsControl。我现在设法创建了一个列表,在该列表中,基于枚举值使用了正确的样式(如下所示)。这是一个小问题:我可以这样做吗,还是应该重写它?如果这样,如何构建这样的东西?关键字或我必须要看的东西对我来说就足够了。
现在我真正的问题是:我已将命令绑定到每个按钮,一开始并不复杂。现在,该命令将其自己的状态设置为NormalActive以进行测试。此列表中的第一项应从LiveActive设置为Live(这样,您将始终看到当前选中的项)。这就是问题所在:按钮可以设置自己的状态,因此当我单击按钮3时,按钮3的状态从“正常”设置为“正常活动”。但是没有发生的是从第一个按钮将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;
}
}
复制步骤:
<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();
}
}
如果现在按下底部的按钮,则该按钮应变为绿色,而顶部的按钮应切换为红色。
答案 0 :(得分:1)
ListViewModel.Instance
都会返回ListViewModel
类的新实例。它应该返回相同的实例:
public static ListViewModel Instance { get; } = new ListViewModel();