【问题标题】:How to find a resource in a UserControl from a DataTemplateSelector class in WPF?如何从 WPF 中的 DataTemplateSelector 类中查找 UserControl 中的资源?
【发布时间】:2009-05-27 14:27:15
【问题描述】:

我正在创建自己的 UserControl,并且在我的 XAML 的 UserControl.Resources 部分下有两个不同的 DataTemplate。我想根据列表视图中显示的对象的属性值在这两个数据模板之间进行选择。为此,我创建了一个自定义 DataTemplateSelector 类并覆盖了应该返回我希望使用的 DataTemplate 的 SelectTemplate 方法。但是,我不知道如何“找到”位于 UserControls 资源部分的数据模板,我看到的所有示例都只从 Window.Resources 获取数据模板。在此示例中,他们获取当前 MainWindow,然后使用 FindResource 查找 DataTemplate,我如何获取我的 UserControl > 以类似的方式?:


public override DataTemplate 
            SelectTemplate(object item, DependencyObject container)
        {
            if (item != null && item is AuctionItem)
            {
                AuctionItem auctionItem = item as AuctionItem;
                Window window = Application.Current.MainWindow;

                switch (auctionItem.SpecialFeatures)
                {
                    case SpecialFeatures.None:
                        return 
                            window.FindResource("AuctionItem_None") 
                            as DataTemplate;
                    case SpecialFeatures.Color:
                        return 
                            window.FindResource("AuctionItem_Color") 
                            as DataTemplate;
                }
            }

            return null;
        }

上面的例子来自这里:ItemsControl.ItemTemplateSelector Property

【问题讨论】:

    标签: c# .net wpf resources wpf-controls


    【解决方案1】:

    我通常在 DataTemplateSelector 的构造函数中使用 UserControl 作为参数从后面的代码中实例化我的 DataTemplateSelector,如下所示:

    public class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            Resources["MyDataTemplateSelector"] = new MyDataTemplateSelector(this);
            InitializeComponent();
        }
    }
    
    public class MyDataTemplateSelector : DataTemplateSelector
    {
        private MyUserControl parent;
        public MyDataTemplateSelector(MyUserControl parent)
        {
            this.parent = parent;
        }
    
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            parent.DoStuff();
        }
    }
    

    不是镇上最漂亮的女孩,但它完成了工作;)

    希望这会有所帮助!

    【讨论】:

    • 有没有办法在 XAML 中做同样的事情?
    • 好的,这很好......但是很高兴知道推荐的方法是什么,最好在 XAML 中完成。
    • 如此真实..我也想知道一种更漂亮的方式..但我认为这个问题实际上不能用 XAML 解决。您需要在后面的代码中提供某种参考,因此最简单的方法是直接提供;)
    • 这似乎也是在 Metro 中完成此任务的唯一方法。由于 Metro 实施的限制,其他选项均无效。
    • 这会创建一个保留周期吗?
    【解决方案2】:

    试试这个:

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (item != null && item is AuctionItem)
            {
                AuctionItem auctionItem = item as AuctionItem;
    
                switch (auctionItem.SpecialFeatures)
                {
                    case SpecialFeatures.None:
                        return 
                            ((FrameworkElement)container).FindResource("AuctionItem_None") 
                            as DataTemplate;
                    case SpecialFeatures.Color:
                        return 
                            ((FrameworkElement)container).FindResource("AuctionItem_Color") 
                            as DataTemplate;
                }
            }
    
            return null;
        }
    

    【讨论】:

      【解决方案3】:
             <DataTemplate x:Key="addTemplate">
              <Button Command="{Binding Path=AddCommand}">Add</Button>
          </DataTemplate>
      
          <DataTemplate x:Key="editTemplate">
              <Button Command="{Binding Path=UpdateCommand}">Update</Button>
          </DataTemplate>
      
          <TemplateSelectors:AddEditTemplateSelector
              AddTemplate="{StaticResource addTemplate}"
              EditTemplate="{StaticResource editTemplate}"
              x:Key="addEditTemplateSelector" />
      

      仅限 XAML!

      【讨论】:

        【解决方案4】:

        WinRT 和 Windows Phone 解决方案涉及向上移动可视化树,直到找到父控件:

            protected override Windows.UI.Xaml.DataTemplate SelectTemplateCore(object item, Windows.UI.Xaml.DependencyObject container)
            {
                var parent = FindParent<MyParentControlType>(container as FrameworkElement);
        
                if(parent != null)
                {
                    if (item is Something)
                        return parent.Resources["TemplateForSomething"] as DataTemplate;
                    else if(item is SomethingElse)
                        return parent.Resources["TemplateForSomethingElse"] as DataTemplate;
                    else 
                        // etc
                }
                else
                {
                    return App.Current.Resources["SomeFallbackResource"] as DataTemplate;
                }
            }
        
            public static T FindParent<T>(FrameworkElement element) where T : FrameworkElement
            {
                FrameworkElement parent = Windows.UI.Xaml.Media.VisualTreeHelper.GetParent(element) as FrameworkElement;
        
                while (parent != null)
                {
                    T correctlyTyped = parent as T;
        
                    if (correctlyTyped != null)
                        return correctlyTyped;
                    else
                        return FindParent<T>(parent);
                }
        
                return null;
            }
        

        FindParent 方法基于此处接受的答案:How to get a ListView from a ListViewItem?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多