3

さまざまな条件に基づいてデータ テンプレートを設定する必要があるコントロールがあるため、DataTemplateSelector割り当て先のコントロールのリソースからテンプレートを選択する を使用することにしました。

これは機能しますが、ここに問題があります。これらのリソースをファイルからリロードしており (ファイル システムの変更がある場合)、既にレンダリングされたコントロールを新しいテンプレートで更新する必要があります。DynamicResourceこれは、セレクターの代わりに単に使用した場合に機能します。

セレクターは次のようになります。

public override DataTemplate SelectTemplate(object item, DependencyObject container) {
  //complex rules that select the template are here
  //this unfortunately sets the template statically - if it changes, it won't get updated
  return template;
}

したがって、リソースが変更された場合、セレクターは、使用した場合のように再評価されることはありませんDynamicResource

これを解決するアイデアがありました。ビューモデルでテンプレートを選択して、リソースが変更されたときにDataTemplateプロパティを更新できるようにします。

私のViewModelの試み(単純化された例、INotifyPropertyChangeを適切に実装しています):

class MyViewModel {
  public DataTemplate DataTemplate {get;set;}

  public MyModel Model {
    get {return _model;}
    set {
      if(_model != value) {
        _model = value;
        //Select new template here
        //DUH: how do I access the resources as I would in DataTemplateSelector, when I don't have access to the container parameter?
      }
    }
  }
}

私はこれを間違った方法で行っていると確信していますが、適切に行うにはどうすればよいですか? さまざまな理由から、ハードコードされた静的な場所からリソースにアクセスしたくありません。割り当てられているコンテナでそれらを見つける必要があります。

質問がわかりにくいので、お気軽に質問してください。明確にしようと思います。

4

1 に答える 1

2

そのため、さまざまなハック的な方法を使用してこれを理解しようとするのに何時間も費やした後、それは本当に簡単に解決できる問題であることがわかりました。

ビューモデルでデータ テンプレート (実際にはデータ テンプレートのキーのみ) を設定し、そのテンプレートを単純な添付プロパティに適用します。

xaml:

<ContentControl Content="{Binding Content}" local:ContentTemplate.ContentTemplateKey="{Binding TemplateKey}">
    <!-- Some other stuff -->
</ContentControl>

添付プロパティ:

public static class ContentTemplate
{

    public static object GetContentTemplateKey(DependencyObject obj)
    {
        return (object)obj.GetValue(ContentTemplateKeyProperty);
    }

    public static void SetContentTemplateKey(DependencyObject obj, object value)
    {
        obj.SetValue(ContentTemplateKeyProperty, value);
    }

    public static readonly DependencyProperty ContentTemplateKeyProperty = DependencyProperty.RegisterAttached("ContentTemplateKey", typeof(object), typeof(ContentTemplate), new UIPropertyMetadata(null, OnContentTemplateKeyChanged));

    private static void OnContentTemplateKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var key = e.NewValue;

        var element = d as FrameworkElement;
        if (element == null)
            return;

        element.SetResourceReference(ContentControl.ContentTemplateProperty, key);
    }
}

リソースが を使用する場合のバインディング オブジェクトx:Key="ResourceName":

new
{
    Content = something,
    TemplateKey = "ResourceName",
}

リソースが を使用する場合のバインディング オブジェクトTargetType="{x:Type Person}":

new
{
    Content = something,
    TemplateKey = new DataTemplateKey(typeof(Person)),
}

もちろん、バインディング オブジェクトは INotifyPropertyChange を実装して、テンプレートがその場で更新されるようにする必要があります。

于 2013-07-04T23:09:07.373 に答える