2012-09-28 46 views
8

这是很容易从代码隐藏的事:如何仅修改WPF控件的保证金属性的右侧(或左侧,顶部,底部)值?

var button = new Button(); 
var margin = button.Margin; 
margin.Right = 10; 
button.Margin = margin; 

在XAML中,不过,我仅限于以下内容:

<Button Margin="0,0,10,0" /> 

这样做的问题是,现在我已经可能通过将其设置为零来覆盖其他边界值(即,左边,顶部,底部))。

有什么办法让XAML像下面这样?

<Button MarginRight="10" /> 

回答

7

可以使用附属的属性。事实上,这正是附加属性的目的:访问父元素属性或向特定元素添加附加功能。

例如,在应用程序中的某处定义以下类:

using System; 
using System.Windows; 
using System.Windows.Controls; 

namespace YourApp.AttachedProperties 
{ 
    public class MoreProps 
    { 
     public static readonly DependencyProperty MarginRightProperty = DependencyProperty.RegisterAttached(
      "MarginRight", 
      typeof(string), 
      typeof(MoreProps), 
      new UIPropertyMetadata(OnMarginRightPropertyChanged)); 

     public static string GetMarginRight(FrameworkElement element) 
     { 
      return (string)element.GetValue(MarginRightProperty); 
     } 

     public static void SetMarginRight(FrameworkElement element, string value) 
     { 
      element.SetValue(MarginRightProperty, value); 
     } 

     private static void OnMarginRightPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) 
     { 
      var element = obj as FrameworkElement; 

      if (element != null) 
      { 
       int value; 
       if (Int32.TryParse((string)args.NewValue, out value)) 
       { 
        var margin = element.Margin; 
        margin.Right = value; 
        element.Margin = margin; 
       } 
      } 
     } 
    } 
} 

现在您的XAML所有你必须做的就是声明如下命名空间:

xmlns:ap="clr-namespace:YourApp.AttachedProperties" 

然后你就可以写XAML如下所示:

<Button ap:MoreProps.MarginRight="10" /> 



或者,可以避免使用附加属性,而是写一些稍微更冗长XAML如:

<Button>
        <Button.Margin>
                <Thickness Right="10" />
        </Button.Margin>
</Button>

+3

这XAML在最后的是同样的事情'保证金=“0,0,10,0”'你覆盖现有的'Thickness'如果有是一个。 –

+1

@ H.B。谢谢,我应该已经测试了最后一部分。你是对的。整个保证金将被重新分配,任何未指定的值将被返回到默认值。我编辑了标记该部分的答案。 – bugged87

0

你错了,这个部分:

var button = new Button(); 
button.Margin.Right = 10; 

埃罗[R CS1612:不能修​​改 “System.Windows.FrameworkElement.Margin”的返回值,因为它不是一个变量

早已不是有效的代码,因为保证金返回struct,因此是值类型。并且因为它不是从DependencyObject派生的,所以很多DataBinding技巧也无法工作。

我只是想给出一个正确的解释,否则我会说你的第一个答案几乎是唯一的方法。

+0

@ dowhilefor您对代码隐藏部分是正确的。在我的部分错别字。我已经更新了我的问题以反映我的实际意思。但是,DataBinding将工作,因为MarginRight属性是一个DependencyObject。因此,无论何时通过绑定更改属性值,都将在回调方法中相应调整保证金。 – bugged87

+0

@ bugged87我的意思是数据绑定,是原来的问题,而不是你附属的答案。当然,这有效的数据绑定。但是在一个厚度为的结构上,除非它的源自然就不能使用数据绑定。总之,我不是在谈论MarginRight,而是在谈论Margin.Right。 – dowhilefor

1

虽然attatched属性可以工作。我会尝试重构你的代码,所以你不会在后面的代码中进行UI更改。您应该尽可能多地处理文件设计方面的UI。我尝试尽可能少地使用xaml文件的代码隐藏,因为它会导致MVVM出现问题。

+1

您对重构代码有任何建议吗?如果XAML设计人员缺乏必需的功能,那么代码隐藏似乎是添加额外功能的好地方。请记住,在单个位置定义和维护的附加属性与在每个XAML文件的代码隐藏中编写该代码并不相同。我想这也取决于你在代码隐藏方面究竟做了些什么。如果你正在修改数据上下文,那么是的,你可能会导致MVVM模式的问题。但是,如果您只是在修改UI组件,那么它可能没问题。 – bugged87

+0

这我一直有一个问题......代码隐藏是一个带有XAML代码的部分类......它与XAML处于同一级别。如果它可以用来完成与UI相关的活动,那么在XAML中做这件事就没什么两样了。 – AshbyEngineer

1

您可以将数据绑定到您的MVVM中的属性(字符串)。在您的MVVM中,您所需要的只是跟踪各个属性(顶部,右侧,底部,右侧)。

您可以使用转换器为:How to set a top margin only in XAML?Binding only part of the margin property of WPF control

+0

数据绑定到我的视图模型中的属性意味着我的视图模型必须保持特定于UI设计的值。这打破了MVVM模式。 – bugged87

+0

我完全同意你的看法......我们在“UI”特定功能之间划定了界限,例如根据状态对行进行着色。如果涉及“逻辑”并且代码依赖于“其他”属性(如服务结果和/或属性),那么MVVM就是......或者,您可以始终附加行为。 –

相关问题