2016-11-11 9 views
0

UWPプロジェクトでは、チームオブジェクトのセットにバインドされたItemsControlを持つUIがあります。ゲームが進行するにつれて変化するCurrentTeamプロパティを持つ別のGameControllerオブジェクトがあります。私は、CurrentTeamであるチームのItemTemplateに視覚的な手がかりを持たせたいと思っています。一例は、現在のチームの名前がアンダーラインになるということです。 TeamオブジェクトにはGameControllerへの参照がありません。条件を使用してItemsControlで表示されるすべてのアイテムを更新するにはどうすればよいですか?

1つの方法は、各チームにフラグを設定して、IsCurrentTeamとItemTemplateのフラグにバインドすることです。私はCurrentTeamが変更されたときに、現在のチーム以外のすべてのチームをループしてフラグを更新する必要があるときに、このアプローチが特に好きではありません。

WPFでは、メソッドにバインドする機能を提供するため、ObjectDataProviderを使用したソリューションがあったと思われますが、UWPのためこのオプションは使用できません。

誰かがこれを行うためのよりよいアプローチを知っていますか?

事前のお手伝いがあります。

+0

GameControllerは、ビュー内の任意の場所(つまり、ItemsControlの外側)にバインドできますか? – ibebbs

+0

@ibebbs、そうです。 – Cleve

答えて

1

[OK]を、私はどのようにこれは達成可能を示す例を用意しました。 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" } 
      } 
     ); 
    } 
} 

あなたが見ることができるように、のコンストラクタページは4つのチームで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をであなたは、私は3つのカスタム添付プロパティに結合していることがわかります。 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); 
    } 
} 

説明するために、CurrentTeamTeam特性は、バインディングによって依存関係オブジェクト(テキストブロック)に設定されています。 Teamプロパティは現在のdatacontextを使用できますが、CurrentTeamプロパティは 'outer' DataContextにバインドする必要があります。これは、ページ上にx:Name="View"を指定し、それを使用してバインディングのElementName=View部分を使用してバインディングでアクセスできるように、datacontextを 'アンカー'することによって行います。

これらのプロパティのいずれかが変更されると、TeamPropertiesChangedコールバックによって同じ依存オブジェクトにIsCurrentTeamプロパティが設定されます。今

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(); 
    } 
} 

、チームは(トップコンボボックスで、使用するどんなメカニズムのプロキシを選択する:ここに示すBoolToFontWeightConverterと(それは下線よりも簡単だったので)IsCurrentTeamプロパティは、その後たfontWeightプロパティにバインドされていますチームを変更する場合)、ItemsControlの該当するチームが太字で表示されます。

私にとってうまく動作します。それが役に立てば幸い。

+0

うわー!そのような詳細な応答をありがとう。努力を本当に感謝します。乾杯。 – Cleve

0

WPFでは、項目のDataContext {Binding}が親のCurrentTeamの内容と等しいときに下線プロパティを設定するDataTriggerが優先されます(これを参照するにはelementnameを使用します)。

UWPはTriggerをサポートしていないため、this postのようにDataTriggerBehaviourを使用できます。

これが役に立ちます。

ユルゲン

+0

こんにちは、お返事ありがとうございます。それをコードに取り入れようとするだけです。 – Cleve

+0

こんにちは、私はあなたがWindows 8のDLLへの参照を追加することを避けたいと思うと思う参照してください投稿の詳細な検査で。 – Cleve

関連する問題