WPF MVVM Пользовательский элемент управления - PullRequest
1 голос
/ 25 февраля 2011

Я пытаюсь создать пользовательский элемент управления облаком тегов.Я хотел бы, чтобы он работал так, чтобы пользователь мог предоставить ему коллекцию строк в itemsSource, и преобразованная строка будет отображаться в пользовательском интерфейсе.

На данный момент у меня есть приложение MVVM облака тегов, которое берет строки коллекции (содержащие дубликаты) и группирует их по «Имени», используя collectionView, а затем конвертер используется для определения FontSize каждой строки.(тег) на основе количества этого string.name в исходной коллекции.

Итак, мой вопрос: как я могу изменить это на желаемый пользовательский элемент управления?Я знаю, что мне придется расширить список в моем коде позади, чтобы выставить itemsSource, но часть, в которой я запутался, - это что делать с логикой группировки (collectionView), так как в настоящее время я привязываюсь к сгруппированной коллекции (без дубликатов), тогда какхотите, чтобы пользователь мог предоставить любую коллекцию.Пожалуйста, дайте мне знать, если это понятно .?

Логика группировки

public class TagCloudControl : ListBox
{
    public ObservableCollection<TagModel> Tags { get; set; }

    static TagCloudControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(TagCloudControl), new FrameworkPropertyMetadata
            (typeof(TagCloudControl)));
    }

    public static DependencyProperty tagsProperty = DependencyProperty.Register("tags",
        typeof(IEnumerable),
        typeof(TagCloudControl));

    public CollectionView GroupedTagsView { get; set; }

    public TagCloudControl()
    {

        ItemsSource = Tags;

        //group my labels by "name" property
        GroupedTagsView = (ListCollectionView)CollectionViewSource.GetDefaultView(Tags);
        GroupedTagsView.GroupDescriptions.Add(new PropertyGroupDescription("Name")); 

    }

    public IEnumerable tags
    {
        get { return (IEnumerable)GetValue(tagsProperty); }
        set { SetValue(tagsProperty, value); }
    }
}

Ответы [ 2 ]

1 голос
/ 25 февраля 2011
  1. Нет причин для расширения ListBox, а не ItemsControl

  2. Почему вы выбираете путь пользовательского элемента управления, а не путь пользовательского элемента управления?

Что бы я сделал, это определил UserControl со свойством зависимости от тегов IEnumerable. Затем я бы связал этот DP с ViewModel (хотя на самом деле нет необходимости использовать MVVM внутри элементов управления, но это действительно ваше дело ...), а затем ViewModel может пройти через эти строки и выставить другую Имущество - Теги ObservableCollection, Где Tag будет выглядеть примерно так:

class Tag
{
    public String Name {get;set}
    public double Size {get;set;}

}

XAML будет содержать только ItemsControl, который будет привязан к списку тегов в ViewModel. Таким образом, все будет работать так, как вы хотите.

<UserControl>
    <ItemsControl ItemsSource="{Binding Tags}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" FontSize="{Binding Size}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>
0 голосов
/ 02 марта 2011

Ниже приведен пример кода, который, я считаю, делает то, что вы ищете. Максимальный размер шрифта жестко задан как 32, но на самом деле это должно быть другое свойство зависимости.

Редактировать: теперь у элемента управления есть DP для коллекций тегов и слов.

XAML:

<UserControl x:Class="TagCloudDemo.TagCloudControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:TagCloudDemo="clr-namespace:TagCloudDemo">

<UserControl.Resources>
    <TagCloudDemo:WeightToSizeConverter x:Key="WeightToSizeConverter" />
</UserControl.Resources>

<ScrollViewer HorizontalScrollBarVisibility="Auto">
    <ItemsControl 
        ItemsSource="{Binding Path=Tags, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TagCloudDemo:TagCloudControl}}}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Path=Name}" FontSize="{Binding Path=Weight, Converter={StaticResource WeightToSizeConverter}}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

Код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace TagCloudDemo
{
    public partial class TagCloudControl : UserControl
    {
        public TagCloudControl()
        {
            InitializeComponent();
        }

        public IEnumerable<string> Words
        {
            get { return (IEnumerable<string>)GetValue(WordsProperty); }
            set { SetValue(WordsProperty, value); }
        }

        public static readonly DependencyProperty WordsProperty =
            DependencyProperty.Register("Words", 
                                        typeof(IEnumerable<string>), 
                                        typeof(TagCloudControl), 
                                        new UIPropertyMetadata(new List<string>(), WordsChanged));

        public IEnumerable<Tag> Tags
        {
            get { return (IEnumerable<Tag>)GetValue(TagsProperty); }
            set { SetValue(TagsProperty, value); }
        }

        public static readonly DependencyProperty TagsProperty =
            DependencyProperty.Register("Tags", 
                                        typeof(IEnumerable<Tag>), 
                                        typeof(TagCloudControl),
                                        new UIPropertyMetadata(new List<Tag>(), TagsChanged));

        private static void WordsChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            TagCloudControl tagCloudControl = sender as TagCloudControl;
            tagCloudControl.Tags = TagCloudDemo.Tag.CreateTags(tagCloudControl.Words);
        }

        private static void TagsChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            TagCloudControl tagCloudControl = sender as TagCloudControl;
            WeightToSizeConverter converter = tagCloudControl.FindResource("WeightToSizeConverter") as WeightToSizeConverter;
            if (converter != null && tagCloudControl.Tags != null)
            {
                converter.MaxWeight = tagCloudControl.Tags.Max(t => t.Weight);
            }
        }
    }

    public class WeightToSizeConverter : IValueConverter
    {
        public int MaxWeight { get; set; }

        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            int weight = (int)value;
            return 32 * MaxWeight / weight;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
        #endregion IValueConverter Members
    }
}

XAML:

<Window x:Class="TagCloudDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:TagCloudDemo="clr-namespace:TagCloudDemo"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TagCloudDemo:TagCloudControl Tags="{Binding Path=Tags}" Grid.Row="0" Background="Red" />
        <TagCloudDemo:TagCloudControl Words="{Binding Path=Words}" Grid.Row="1" Background="Yellow" />
    </Grid>
</Window>

Код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace TagCloudDemo
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            DataContext = new VM();
        }
    }

    public class VM
    {
        public VM()
        {
            Words = LoadWords();
            Tags = Tag.CreateTags(Words);
        }

        public IEnumerable<string> Words { get; private set; }

        public IEnumerable<Tag> Tags { get; private set; }

        private static IEnumerable<string> LoadWords()
        {
            Random random = new Random();

            string loremIpsum =
                "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
            string[] tokens = loremIpsum.Split(new char[] {' '});
            List<string> words = new List<string>();
            for (int i = 0; i < 500; i++)
            {
                words.Add(tokens[random.Next(tokens.Count())]);
            }
            return words;
        }
    }

    public class Tag
    {
        public Tag(string name, int weight)
        {
            Name = name;
            Weight = weight;
        }

        public string Name { get; set; }
        public int Weight { get; set; }

        public static IEnumerable<Tag> CreateTags(IEnumerable<string> words)
        {
            Dictionary<string, int> tags = new Dictionary<string, int>();
            foreach (string word in words)
            {
                int count = 1;
                if (tags.ContainsKey(word))
                {
                    count = tags[word] + 1;
                }
                tags[word] = count;
            }

            return tags.Select(kvp => new Tag(kvp.Key, kvp.Value));
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...