c# - 在 MVVM 中动态填充 Wrappannel

标签 c# wpf mvvm mvvm-toolkit

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

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

我在后面的代码中做到了这一点。现在我正在将整个事情转移到 MVVM 模型的过程中,我坚持在不影响 MVVM 核心原则的情况下执行此操作。在这段代码中,我将 UI 元素和逻辑内容放在一起,它们紧密相关;而且我已经无法将两者分开以安装 MVVM。

我尝试在 VM 中创建 UI 元素,填充 UIElement 类型的 ObservableCollection 并将其绑定(bind)到 itemssource 属性(随后我将 wrappanel 更改为 listview 以便在整个过程中有效)。但这并没有奏效,因为当我绑定(bind)元素时,代码无法理解哪个 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);

    }

非常感谢任何帮助!

最佳答案

正如我所 promise 的,我创建了一个示例,其中 ViewModels 中没有 UIElements

首先,我从你的方法中删除了很多代码:

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);

关于c# - 在 MVVM 中动态填充 Wrappannel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5429988/

相关文章:

c# - 数组写入的性能影响比预期的要大得多

c# - WPF mvvm 绑定(bind),获取/设置值 : issue with preventing update value

C# WPF 单选按钮拆分到不同的页面

c# - 依赖注入(inject) - 处理多次注入(inject)的简洁方法

wpf - 将 MergedDictionary 添加到 Application.Resources WPF 时出错

c# - FileResult + redirectToAction出现错误

javascript - 正则表达式限制小数点后两位

c# - 序列化 GradientBrush

c# - 在触发器中检查窗口的 "WindowState"的值

c# - 在 MVVM 中绑定(bind)事件并将事件参数作为命令参数传递