Динамическое заполнение Wrappannel в MVVM - PullRequest
1 голос
/ 25 марта 2011

Это относится к рекомендациям по использованию MVVM.

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

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

Я попытался создать элементы пользовательского интерфейса в виртуальной машине, заполнив ObservableCollection типа UIElement и связав его со свойством itemssource (Впоследствии я изменил оболочку наlistview, чтобы быть эффективным в целом).Но это не сработало, поскольку, когда я связываю элементы, код не может понять, какой именно UIelement.

Ниже приведен раздел кода, который мне нужно разделить:

private void CreateVisulaQueryContent() {

            VisualQueryObject visualQueryData = new VisualQueryObject();

            VisualQueryObject helperVisualQueryObject = DraggedData as    VisualQueryObject;


            //***Taking a copy of the static DraggedData object to be bound

                visualQueryData.ColumnDiscriptor = helperVisualQueryObject.ColumnDiscriptor;

            visualQueryData.ComparedValue = helperVisualQueryObject.ComparedValue;

            visualQueryData.JoinWithColumnDescriptor = helperVisualQueryObject.JoinWithColumnDescriptor;

            visualQueryData.LabelType = helperVisualQueryObject.LabelType;
            visualQueryData.OperatorValue = helperVisualQueryObject.OperatorValue;


            if (visualQueryData.LabelType == "column")
            {

                ColumnDescriptionObject descriptionValue = visualQueryData.ColumnDiscriptor;
                Label droppedElement = new Label();

                Binding binding = new Binding();
                binding.Source = visualQueryData;
                binding.Path = new PropertyPath("ColumnDiscriptor");
                binding.Mode = BindingMode.TwoWay;
                droppedElement.SetBinding(Label.DataContextProperty, binding);

                droppedElement.Content = visualQueryData.ColumnDiscriptor.TableName + "." + visualQueryData.ColumnDiscriptor.ColumnName;


                droppedElement.Foreground = Brushes.White;
                droppedElement.Background = Brushes.DarkOrange;

                droppedElement.BorderThickness = new Thickness(5);

                droppedLabel.MouseDoubleClick += columnLabel_MouseDown;
                ViewUIElements.Add(droppedElement);

            }
            else if (visualQueryData.LabelType == "controller")
            {

                Label droppedElement = new Label();

                Binding binding = new Binding();
                binding.Source = visualQueryData;
                binding.Path = new PropertyPath("OperatorValue");
                binding.Mode = BindingMode.TwoWay;
                droppedElement.SetBinding(Label.DataContextProperty, binding);


                droppedElement.Content = draggedContent.OperatorValue;
                droppedElement.Foreground = Brushes.White;
                droppedElement.Background = Brushes.Crimson;
                droppedElement.BorderThickness = new Thickness(5);

                droppedElement.MouseDoubleClick += columnLabel_MouseDown;

                ViewUIElements.Add(new Label());

            }
            else if (visualQueryData.LabelType == "value")
            {
                TextBox droppedElement = new TextBox();

                Binding binding = new Binding();
                binding.Source = visualQueryData;
                binding.Path = new PropertyPath("ComparedValue");
                binding.Mode = BindingMode.TwoWay;
                droppedElement.SetBinding(TextBox.TextProperty, binding);

               droppedElement.MouseDoubleClick += columnLabel_MouseDown;

                ViewUIElements.Add(droppedElement);
            }

            QueryDesignerModel.QueryDesignHelperCollection.Add(visualQueryData);

    }

Любая помощь высоко ценится!

Ответы [ 2 ]

3 голосов
/ 25 марта 2011

Как я и обещал, я создал пример, в котором нет UIElements внутри ViewModels.

Прежде всего, я удалил много кода из вашего метода:

public class MainViewModel
{
    public MainViewModel()
    {
        //For demonstration
        this.ViewUIElements = new ObservableCollection<VisualQueryObject>
        {
            new VisualQueryObject{LabelType = "column", ColumnDiscriptor = new DescriptionModel("Table1", "Column2") },
            new VisualQueryObject{LabelType = "controller"},
            new VisualQueryObject{LabelType = "value"},
        };
    }

    public void UpdateCollection(VisualQueryObject helperVisualQueryObject)
    {
        VisualQueryObject visualQueryData = new VisualQueryObject();
        //I would remove copying, but maybe it is intended behavior
        //***Taking a copy of the static DraggedData object to be bound           
        visualQueryData.ColumnDiscriptor = helperVisualQueryObject.ColumnDiscriptor;
        visualQueryData.ComparedValue = helperVisualQueryObject.ComparedValue;
        visualQueryData.JoinWithColumnDescriptor = helperVisualQueryObject.JoinWithColumnDescriptor;
        visualQueryData.LabelType = helperVisualQueryObject.LabelType;
        visualQueryData.OperatorValue = helperVisualQueryObject.OperatorValue;

        this.ViewUIElements.Add(visualQueryData);

        //QueryDesignerModel.QueryDesignHelperCollection.Add(visualQueryData);   //I don't know what this method does
    }

    public ObservableCollection<VisualQueryObject> ViewUIElements { get; private set; }
}

Затем я создал класс DataTemplateSelector, в который я поместил предложения if из функции в вашем вопросе:

public class QueryObjectDateTemplateSelector : DataTemplateSelector
{
    public DataTemplate ColumnTemplate { get; set; }

    public DataTemplate ControllerTemplate { get; set; }

    public DataTemplate ValueTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
    {
        var visualQueryData = item as VisualQueryObject;
        if (visualQueryData == null)
            return null;

        if (visualQueryData.LabelType == "column")
            return ColumnTemplate;
        else if (visualQueryData.LabelType == "controller")
            return ControllerTemplate;
        else if (visualQueryData.LabelType == "value")
            return ValueTemplate;
        else return null;

    }
}

И это почти все. Все остальное в xaml:

<Window.Resources>
    <ItemsPanelTemplate x:Key="WrapPanelTemplate">
        <WrapPanel Orientation="Horizontal" />
    </ItemsPanelTemplate>

    <DataTemplate x:Key="ColumnDataTemplate">
        <Label DataContext="{Binding ColumnDiscriptor}" Foreground="White" Background="DarkOrange" BorderThickness="5">
            <TextBlock>
                <Run Text="{Binding TableName}"/><Run Text="."/><Run Text="{Binding ColumnName}"/> 
            </TextBlock>
        </Label>
    </DataTemplate>
    <DataTemplate x:Key="ControllerDataTemplate">
        <Label Content="Controller"/>
    </DataTemplate>
    <DataTemplate x:Key="ValueDataTemplate">
        <TextBox Text="Value"/>
    </DataTemplate>
    <local:QueryObjectDateTemplateSelector x:Key="ModelSelector"
                                           ColumnTemplate="{StaticResource ColumnDataTemplate}"
                                           ControllerTemplate="{StaticResource ControllerDataTemplate}"
                                           ValueTemplate="{StaticResource ValueDataTemplate}"/>
</Window.Resources>
<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>

<Grid>
    <ItemsControl ItemsSource="{Binding ViewUIElements}" ItemsPanel="{StaticResource WrapPanelTemplate}" 
                  ItemTemplateSelector="{StaticResource ModelSelector}"/>
</Grid>

Я кодировал только шаблон столбца, другие шаблоны должны быть переписаны также на xaml. Теперь вы можете вызвать этот метод:

((MainViewModel)this.DataContext).UpdateCollection(DraggedData as VisualQueryObject);
1 голос
/ 25 марта 2011

Я не совсем уверен, что вы ищете, но звучит так, будто вы хотите использовать шаблонизацию данных, чтобы изменить ItemTemplate для ListBox на основе базового связанного типа объекта данных.

Итак, в вашем случае вы можете иметь ObservableCollection<LabelType>, где тип метки имеет производные типы для каждого из ваших типов меток (столбец, контроллер, значение), а затем использовать неявные шаблоны данных (используя свойство DataType), чтобы выбрать соответствующий шаблон для каждого подтипа.

В качестве альтернативы вы можете иметь один LabelType с перечислением для типа объекта.

ObservableCollection<LabelType> Labels ...

Labels.Add(new ControllerLabelType());

...

<ListBox ItemsSource="{Binding Labels}">
  <ListBox.Resources>
    <DataTemplate DataType="{x:Type local:ControllerLabelType}">
      <TextBlock Text="{Binding OperatorValue}" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:ValueLabelType}">
      <TextBox Text="{Binding OperatorValue}" />
    </DataTemplate>        
  </ListBox.Resources>
  <ListBox.ItemsPanel>
    <ItemsPanelTemplate>
      <WrapPanel IsItemsHost="True" />
    </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
</ListBox>    

Подробнее о шаблонах данных см. http://msdn.microsoft.com/en-us/library/ms742521.aspx.

...