这是关于使用 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/