在 MVVM 中动态填充 Wrappannel
这是关于使用 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);
}
非常感谢任何帮助!
this is regarding a best practice advice regarding using MVVM.
I am in need to populate a wrappanel as and when elements are dropped in to it. The elements are not uniform, they can be either labels or text boxes. Depending on a value of a parameter the element added varies.
I did this in code behind. Now I am in the process of moving the entire thing to an MVVM model am stuck with the way to do this without affecting the MVVM core principals. In this code I have both UI elements and logic content to gether which are tightly related; and I have become incapable to seperate the two to suite MVVM.
I tried creating the UI elements in the VM, populating a ObservableCollection of type UIElement and binding it to the itemssource property (Subsequently I changed wrappanel to be a listview to be effective in the whole thing). But this did not work out since when I bind the elements there is no way the code can understand which UIelement.
Posted below is the section of the code which I need to seperate:
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);
}
Any help is deeply appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如我所承诺的,我创建了一个示例,其中
ViewModels
内没有UIElements
。首先,我从你的方法中删除了很多代码:
然后我创建了
DataTemplateSelector
类,我在你的问题中的函数中放置了 if 子句:这几乎就是全部。其他所有内容都在 xaml 中:
我只编码了列模板,其他模板也应该在 xaml 中重写。
所以现在你可以调用这个方法:
As I promised, I have created an example in which there is no
UIElements
insideViewModels
.First of all, I removed lot of code from your method:
Then I created the
DataTemplateSelector
class where I've put if-clauses from the function in your question:And that's almost all. Everything else is in
xaml
:I have coded only the Column Template, other templates should be rewritten in xaml too.
So now you can call this method:
我不太确定您想要什么,但听起来您想使用数据模板根据底层绑定数据对象类型更改
ListBox
的ItemTemplate
。因此,在您的情况下,您可以拥有一个
ObservableCollection
,其中标签类型具有每个标签类型(列、控制器、值)的派生类型,然后使用隐式数据模板(使用DataType
属性)为每个子类型选择合适的模板。或者,您可以使用一个带有对象类型枚举的
LabelType
。请参阅 http://msdn.microsoft.com/en-us/library/ms742521。有关数据模板的更多信息,请访问 http://www.aspx。
I'm not quite sure what you are after, but it sounds like you want to use data templating to change the
ItemTemplate
for aListBox
based on the underlying bound data object type.So, in your case you can have an
ObservableCollection<LabelType>
where label type has derived types for each of your label types (column, controller, value), then use implicit data templates (using theDataType
property) to select an appropriate template for each sub type.Alternatively, you could have one
LabelType
with an enumeration for the type of object.See http://msdn.microsoft.com/en-us/library/ms742521.aspx for more on data templating.