在UWP项目中,我有一个UI,其中ItemsControl绑定到一组Team对象。有一个单独的GameController对象,其CurrentTeam属性随着游戏的进展而变化。我希望能够在ProjectTemplate中为CurrentTeam团队提供视觉提示。一个例子是当前团队的名字被加下划线说。 Team对象没有对GameController的引用。
一种方法是在每个Team上放置一个标志,比如说IsCurrentTeam并绑定到ItemTemplate中的那个。我并不特别喜欢这种方法,因为这意味着当CurrentTeam发生变化时,我必须绕过除当前团队之外的所有团队,以更新他们的标志。
在WPF中我认为可能有一个使用ObjectDataProvider的解决方案,因为它提供了绑定到方法的能力,但由于我在UWP中这个选项不可用。
有没有人知道更好的方法呢?
答案 0 :(得分:1)
好的,我已经准备了一个展示如何实现这一目标的例子。为了解决UWP中的限制,它使用了一些技术,例如数据上下文锚定'和附属物。
这是我的支持课程,我认为它们与你的有点类似:
public class GameControllerViewModel : INotifyPropertyChanged
{
private Team _currentTeam;
public event PropertyChangedEventHandler PropertyChanged;
public GameControllerViewModel(IEnumerable<Team> teams)
{
Teams = teams;
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Team CurrentTeam
{
get { return _currentTeam; }
set
{
if (value != _currentTeam)
{
_currentTeam = value;
OnPropertyChanged();
}
}
}
public IEnumerable<Team> Teams { get; private set; }
}
public class Team
{
public string Name { get; set; }
}
页面背后的代码:
public sealed partial class GamesPage : Page
{
public GamesPage()
{
this.InitializeComponent();
this.DataContext = new GameControllerViewModel(
new[]
{
new Team { Name = "Team A" },
new Team { Name = "Team B" },
new Team { Name = "Team C" },
new Team { Name = "Team D" }
}
);
}
}
正如您所看到的,页面的构造函数实例化了一个包含四个团队的GameControllerViewModel,并将其设置为页面的数据上下文。
页面XAML如下:
<Page
x:Class="UniversalScratchApp.GamesPage" x:Name="View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UniversalScratchApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<local:BoolToFontWeightConverter x:Key="BoolToFontWeightConverter"/>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Current Team:" Margin="4" VerticalAlignment="Center"/>
<ComboBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding Teams}" SelectedItem="{Binding CurrentTeam, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" Margin="4">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ItemsControl Grid.Row="1" Grid.ColumnSpan="2" ItemsSource="{Binding Teams}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" local:TeamProperties.CurrentTeam="{Binding ElementName=View, Path=DataContext.CurrentTeam}" local:TeamProperties.Team="{Binding}" FontWeight="{Binding Path=(local:TeamProperties.IsCurrentTeam), RelativeSource={RelativeSource Mode=Self}, Mode=OneWay, Converter={StaticResource BoolToFontWeightConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Page>
在ItemsControl的DataTemplate中,您可以看到我绑定到三个自定义附加属性; TeamProperties.CurrentTeam
,TeamProperties.Team
和TeamProperties.IsCurrentTeam
。附加属性在以下类中定义:
[Bindable]
public static class TeamProperties
{
private static void TeamPropertiesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
Team team = GetTeam(sender);
Team currentTeam = GetCurrentTeam(sender);
if (team != null && currentTeam != null)
{
SetIsCurrentTeam(sender, team.Equals(currentTeam));
}
}
public static readonly DependencyProperty CurrentTeamProperty = DependencyProperty.RegisterAttached("CurrentTeam", typeof(Team), typeof(TeamProperties), new PropertyMetadata(null, TeamPropertiesChanged));
public static Team GetCurrentTeam(DependencyObject obj)
{
return (Team)obj.GetValue(CurrentTeamProperty);
}
public static void SetCurrentTeam(DependencyObject obj, Team value)
{
obj.SetValue(CurrentTeamProperty, value);
}
public static readonly DependencyProperty TeamProperty = DependencyProperty.RegisterAttached("Team", typeof(Team), typeof(TeamProperties), new PropertyMetadata(null, TeamPropertiesChanged));
public static Team GetTeam(DependencyObject obj)
{
return (Team)obj.GetValue(TeamProperty);
}
public static void SetTeam(DependencyObject obj, Team value)
{
obj.SetValue(TeamProperty, value);
}
public static readonly DependencyProperty IsCurrentTeamProperty = DependencyProperty.RegisterAttached("IsCurrentTeam", typeof(bool), typeof(TeamProperties), new PropertyMetadata(false));
public static bool GetIsCurrentTeam(DependencyObject obj)
{
return (bool)obj.GetValue(IsCurrentTeamProperty);
}
public static void SetIsCurrentTeam(DependencyObject obj, bool value)
{
obj.SetValue(IsCurrentTeamProperty, value);
}
}
为了解释,绑定对依赖项对象(文本块)设置了CurrentTeam
和Team
属性。虽然Team
属性可以使用当前的datacontext,但CurrentTeam
属性必须绑定到&#39;外部&#39; DataContext的。它是通过在页面上指定x:Name="View"
并使用它来锚定&#39;来实现的。 datacontext然后可以使用绑定的ElementName=View
部分通过绑定来访问。
因此,每当这些属性中的任何一个发生更改时,IsCurrentTeam
回调都会在同一个依赖项对象上设置TeamPropertiesChanged
属性。然后使用此处显示的BoolToFontWeightConverter将IsCurrentTeam
属性绑定到FontWeight属性(因为它比下划线更容易):
public class BoolToFontWeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is bool)
{
return ((bool)value) ? FontWeights.ExtraBold : FontWeights.Normal;
}
else
{
return DependencyProperty.UnsetValue;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotSupportedException();
}
}
现在,当在顶级组合框中选择一个团队(代理您用于更改团队的任何机制)时,ItemsControl
中的相应团队将以粗体显示。
很适合我。希望它有所帮助。
答案 1 :(得分:0)
在WPF中,我首选的选项是DataTrigger,当项的DataContext {Binding}
等于父项的CurrentTeam
的内容时设置下划线属性(使用元素名来引用它)。
由于UWP不支持触发器,您可以使用this post中的DataTriggerBehaviour
。