我正在使用C#
和Blend
并正在处理WPF
申请。我试图创建自己的控件来列出项目 - 例如文件名。我使用的是StackPanel
,每个文件名都是自定义UserControl
。我所追求的是,当点击StackPanel.Children
中的UserControl时,UserControl
会突出显示(预定义的视觉状态),而其他所有状态都不会突出显示。我已经在UserControl端代码中获得了Click事件,但是我试图实现它以告诉所有其他UserControl没有被点亮。我已经向UserControl添加了一个名为Selected
的可公开访问的属性,因此可能认为主程序可能会更改它,然后使用UserControl代码检测何时更改,并更改它的视觉效果国家不强调。它本质上是一个关闭多选的列表框!感谢
修改
private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
{
if (Selected == false)
{
VisualStateManager.GoToState(this, "Highlighted", true);
Selected = true;
}
else
{
VisualStateManager.GoToState(this, "Normal", true);
Selected = false;
}
}
答案 0 :(得分:2)
这里快速演示了如何仅在XAML中完全更改列表框项的外观和行为。这里的所有C#代码只是定义和填充列表框中显示的集合。在两个不同的列表框中有两个集合,以证明编写一个通用的(通用的,通用的,而不是Foo<T>
意义上的Generic)项容器模板的价值,该模板不知道你是什么类型的内容。投入其中。
实际上,它是您如何思考XAML / MVVM中的UI编程的一个非常基础的入门读物。 MVVM是一种不同的思维方式。像OOP一样,看起来很随意,直到你理解,然后它被认为是非常强大的。
如果你仔细考虑这段代码,直到你理解了它所做的一切,你就会迈出启蒙的第一步。所有这些代码都是死记硬背,数字化的东西。一旦掌握了概念,在任何远程正常情况下应用它们都不具有挑战性。这可以让你保存脑细胞以寻找真正具有挑战性的东西。
首先,我们将编写一个包含类似,东西和东西的快速视图模型。
ViewModels.cs
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace CustomListBox
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] String propName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class ThingViewModel : ViewModelBase
{
#region Name Property
private String _name = "";
public String Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
OnPropertyChanged();
}
}
}
#endregion Name Property
}
public class MainViewModel : ViewModelBase
{
#region Things Property
private ObservableCollection<ThingViewModel> _things = new ObservableCollection<ThingViewModel>();
public ObservableCollection<ThingViewModel> Things
{
get { return _things; }
set
{
if (value != _things)
{
_things = value;
OnPropertyChanged();
}
}
}
#endregion Things Property
#region Stuff Property
private ObservableCollection<object> _stuff = new ObservableCollection<object>();
public ObservableCollection<object> Stuff
{
get { return _stuff; }
set
{
if (value != _stuff)
{
_stuff = value;
OnPropertyChanged();
}
}
}
#endregion Stuff Property
}
}
我们将在主窗口的代码隐藏构造函数中使用一些任意的东西和其他内容来填充主视图模型的集合。
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Collections.ObjectModel;
namespace CustomListBox
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel.Things = new ObservableCollection<ThingViewModel>(
Directory.GetFiles("c:\\").Select(fn => new ThingViewModel { Name = fn }));
ViewModel.Stuff = new ObservableCollection<Object>(
Enumerable.Range(1, 10).Select(n => new { Blah = Math.Log(n), Foobar = n }));
ViewModel.Stuff.Insert(0, new { Blah = "Different type, same name", Foobar = "LOL" });
}
public MainViewModel ViewModel => (MainViewModel)DataContext;
}
}
这就是XAML:
<Window
x:Class="CustomListBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CustomListBox"
mc:Ignorable="d"
Title="MainWindow" Height="400" Width="600">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Window.Resources>
<Style x:Key="UglySelectionListBox" TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<!-- Need this so the whole listbox item is clickable -->
<Setter Property="IsHitTestVisible" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border
x:Name="BackgroundBorder"
BorderThickness="2"
CornerRadius="4"
Margin="0"
Padding="4"
Background="Transparent"
BorderBrush="#01ffffff"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Path
x:Name="SelectionMark"
Stroke="Black"
StrokeThickness="2"
Data="M0,8 L 4,12 L 10,0"
Visibility="Hidden"
/>
<!--
The ContentPresenter presents the Content property of the ListBoxItem.
The ItemTemplate or DisplayMemberPath determine what the Content actually is
-->
<ContentPresenter ContentSource="Content" Grid.Column="1" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="Silver" />
<Setter TargetName="BackgroundBorder" Property="Background" Value="Gainsboro" />
<Setter TargetName="SelectionMark" Property="Stroke" Value="Silver" />
<Setter TargetName="SelectionMark" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="BackgroundBorder" Property="Background" Value="LightSkyBlue" />
<Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="Red" />
<Setter TargetName="BackgroundBorder" Property="TextElement.FontWeight" Value="Bold" />
<Setter TargetName="SelectionMark" Property="Stroke" Value="Black" />
<Setter TargetName="SelectionMark" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel
Grid.Column="0"
Orientation="Vertical"
>
<!--
ListBox.SelectedValue goes to the selected item, and returns the
value of the property named by SelectedValuePath
-->
<TextBlock
Text="{Binding SelectedValue, ElementName=StuffBox}"
ToolTip="This displays the 'value' of the SelectedItem in the left listbox"
/>
<ListBox
ItemsSource="{Binding Stuff}"
Style="{StaticResource UglySelectionListBox}"
DisplayMemberPath="Blah"
SelectedValuePath="Foobar"
Background="Beige"
x:Name="StuffBox"
/>
</StackPanel>
<ListBox
Grid.Column="1"
ItemsSource="{Binding Things}"
Style="{StaticResource UglySelectionListBox}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
行。我们看到我们可以在ListBox
中显示各种内容。 ListBoxItem
模板确定ListBoxItem
本身的外观和行为,除了内容之外的所有内容。然后我们可以根据我们填充ListBox
的内容在其中放置不同类型的内容。我们可以命名要显示的属性(如在StuffBox中),或者提供一个项目DataTemplate,它为我们提供了更多选项 - 您可以将所有XAML孩子都放在该模板中。它可以有自己的触发器。你喜欢的都可以。试试这个lolz:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<ListBox ItemsSource="{Binding Name}" />
</StackPanel>
</DataTemplate>
String
实施IEnumerable<T>
。它是一系列人物。因此,您可以将其用作ItemsSource
的{{1}}。你可以用这些东西绝对疯狂。