简体   繁体   English

如何绑定UserControl中的多个属性

[英]How to bind multiple properties in a UserControl

Let's say we have a UserControl like this: 假设我们有一个像这样的UserControl:

<UserControl x:Class="...>
    <StackPanel>
        <TextBlock Name="TextBlock1" />
        <TextBlock Name="TextBlock2" />
        <TextBlock Name="TextBlock3" />
        ...
        <TextBlock Name="TextBlock10" />
    </StackPanel>
</UserControl>

And we have properties defined like this: 我们有如下定义的属性:

public string Text1 { get; set; }
public string Text2 { get; set; }
public string Text3 { get; set; }
...
public string Text10 { get; set; }

And know I want to bind all those TextBlocks to all those properties. 并且知道我想将所有这些TextBlocks绑定到所有这些属性。 There are obviously multiple ways of doing this and I wonder about the (dis-)advantages of the different ones. 显然有多种方法可以做到这一点,我想知道不同方法的优点(dis-)。 Let's make a list: 我们列一个清单:

  1. My first approach was this: 我的第一个方法是:

     <TextBlock Name="TextBlock1" Text="{Binding Path=Text1, RelativeSource={RelativeSource AncestorType=UserControl}}" /> 

    This works and is fairly simple, but it is a lot of redundant code if I have to type it for all the TextBlocks. 这工作并且相当简单,但如果我必须为所有TextBlocks键入它,则会有很多冗余代码。 In this example we could just copy-paste, but the UserControl could be more complex. 在这个例子中,我们可以只复制粘贴,但UserControl可能更复杂。

  2. When I googled the problem I found this solution: 当我用Google搜索问题时,我发现了这个解决方案:

     <UserControl ... DataContext="{Binding RelativeSource={RelativeSource Self}}"> <TextBlock Name="TextBlock1" Text="{Binding Path=Text1}" /> 

    This looks pretty clean in the xaml, however DataContext could be used otherwise. 这在xaml中看起来很干净,但是否则可以使用DataContext。 So if someone uses this UserControl and changes the DataContext, we are screwed. 因此,如果有人使用此UserControl并更改DataContext,我们就会搞砸了。

  3. Another common solution seems to be this: 另一个常见的解决方案似乎是:

     <UserControl ... x:Name="MyUserControl"> <TextBlock Name="TextBlock1" Text="{Binding Path=Text1, ElementName=MyUserControl}" /> 

    This has the same problem as 2. though, Name could be set from somewhere else. 这与2的问题相同。但是,Name可以从其他地方设置。

  4. What if we write our own MarkupExtension? 如果我们编写自己的MarkupExtension怎么办?

     public class UserControlBindingExtension : MarkupExtension { public UserControlBindingExtension() { } public UserControlBindingExtension(string path) { this.Path = path; } private Binding binding = null; private string path; [ConstructorArgument("path")] public string Path { get { return path; } set { this.path = value; binding = new Binding(this.path); binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(UserControl), 1); } } public override object ProvideValue(IServiceProvider serviceProvider) { if(binding == null) return null; return binding.ProvideValue(serviceProvider); } } 

    Now we can do something like this: 现在我们可以这样做:

     <UserControl ... xmlns:self="clr-namespace:MyProject"> <TextBlock Name="TextBlock1" Text="{self:UserControlBinding Path=Text1}" 

    Neat! 整齐! But I'm not conviced if my implementation is bulletproof and I would prefer not writing my own MarkupExtension. 但是,如果我的实现是防弹的,我不相信我不想写自己的MarkupExtension。

  5. Similar to 4. we could do this: 与4.类似,我们可以这样做:

     public class UserControlBindingHelper : MarkupExtension { public UserControlBindingHelper() { } public UserControlBindingHelper(Binding binding) { this.Binding = binding; } private Binding binding; [ConstructorArgument("binding")] public Binding Binding { get { return binding; } set { binding = value; binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(UserControl), 1); } } public override object ProvideValue(IServiceProvider serviceProvider) { if (binding == null) return null; return binding.ProvideValue(serviceProvider); } } 

    Which would result in code like this: 这会产生如下代码:

     <TextBlock Name="TextBlock1" Text="{self:UserControlBindingHelper {Binding Text1}}" /> 
  6. We could do it in code! 我们可以在代码中完成它!

     private void setBindingToUserControl(FrameworkElement element, DependencyProperty dp, string path) { Binding binding = new Binding(path); binding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(StateBar), 1); element.SetBinding(dp, binding); } 

    And then we do this: 然后我们这样做:

     setBindingToUserControl(this.TextBlock1, TextBlock.Text, "Text1"); 

    Fairly nice, but it makes the xaml harder to read, since the information about the bindings is missing now. 相当不错,但它使得xaml更难阅读,因为现在缺少有关绑定的信息。

  7. What other good/interesting options are there? 还有哪些好的/有趣的选择?

So what is the way to go in which situation? 那么在哪种情况下走的路是什么? Did I make a mistake somewhere? 我在某个地方犯了错误吗?
To specify the question: 要指定问题:
Are all those ways correct? 这些都是正确的吗? Are some superior to others? 有些优于其他人吗?

It looks like you've made a lot of good tests here! 看起来你已经在这里做了很多好的测试! As you've probably already noticed, most of your ways of doing it are working, but i would recommend using your first approach. 正如您可能已经注意到的那样,您的大部分工作方式都有效,但我建议您使用第一种方法。 While it might look a bit repetitive, it is very explicit and fairly simple to maintain. 虽然它可能看起来有点重复,但它非常明确且维护起来相当简单。 It also makes your code easily readable by anyone who's not so expert in xaml. 它还使任何不太熟悉xaml的人都可以轻松阅读您的代码。

You already know the issues with solution 2 and 3. Creating your own markup extension is a bit overkill(at least in this case) and makes your code harder to understand. 您已经知道解决方案2和3的问题。创建自己的标记扩展有点矫枉过正(至少在这种情况下)并且使您的代码更难理解。 Solution 6 works fine but as you said, it makes it impossible to know to what the textblock is bind to within the xaml. 解决方案6工作正常但正如您所说,它使得无法知道文本块在xaml中绑定的内容。

Just use #2, and assume the DataContext is correct. 只需使用#2,并假设DataContext是正确的。 Thats the standard. 这是标准。 It's the responsibility of the person who uses the User Control to ensure that the DataContext is set correctly. 使用用户控件的人员有责任确保正确设置DataContext。

Anything else is just adding unnecessary complexity. 其他任何东西只会增加不必要的复杂性。

See ReSharper WPF error: "Cannot resolve symbol "MyVariable" due to unknown DataContext" . 请参阅ReSharper WPF错误:“由于未知的DataContext,无法解析符号”MyVariable“

Its common practice for anyone using a User Control to set up the DataContext to RelativeSource Self see How do I bind to RelativeSource Self? 对于任何使用用户控件将DataContext设置为RelativeSource Self人来说,这是常见的做法,请参阅如何绑定到RelativeSource Self?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM