1

这是关于使用 MVVM 的最佳实践建议。

当元素被放入其中时,我需要填充一个包装面板。元素不统一,它们可以是标签或文本框。根据参数的值,添加的元素会有所不同。

我在后面的代码中做到了这一点。现在我正在将整个事情转移到一个 MVVM 模型中,我坚持这样做的方法而不影响 MVVM 核心原则。在这段代码中,我同时拥有紧密相关的 UI 元素和逻辑内容;而且我已经无法将两者分开以适应 MVVM。

我尝试在 VM 中创建 UI 元素,填充 UIElement 类型的 ObservableCollection 并将其绑定到 itemssource 属性(随后我将 wrappanel 更改为 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);

    }

任何帮助都深表感谢!

4

2 回答 2

3

正如我所承诺的,我创建了一个没有UIElementsinside的示例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);
于 2011-03-25T19:24:17.467 回答
1

我不太确定你在追求什么,但听起来你想使用数据模板来更改基于底层绑定数据对象类型 的ItemTemplatefor a 。ListBox

因此,在您的情况下,您可以ObservableCollection<LabelType>为每个标签类型(列、控制器、值)使用 where 标签类型派生类型,然后使用隐式数据模板(使用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

于 2011-03-25T11:44:05.233 回答