【问题标题】:How do I modify ONLY the right (or left, top, bottom) value of a WPF control's Margin property?如何仅修改 WPF 控件的 Margin 属性的右侧(或左侧、顶部、底部)值?
【发布时间】:2012-09-19 20:53:31
【问题描述】:

这在代码隐藏中很容易做到:

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" />

【问题讨论】:

    标签: wpf xaml mvvm wpf-controls mvvm-light


    【解决方案1】:

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

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

    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,例如:

    &lt;Button&gt;
    &lt;Button.Margin&gt;
    &lt;Thickness Right="10" /&gt;
    &lt;/Button.Margin&gt;
    &lt;/Button&gt;

    【讨论】:

    • 最后的 XAML 与 Margin="0,0,10,0" 相同,因为如果存在 Thickness,则覆盖现有的 Thickness
    • @H.B.谢谢,我应该已经测试了最后一部分。你说得对。整个边距将被重新分配,任何未指定的值都将返回默认值。我已经编辑了答案以标记该部分。
    • 不幸的是,这不起作用,在设置附加属性时,Margin 尚未设置,所以我修改了默认的 0 边距,而不是 XAML 中指定的边距
    【解决方案2】:

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

    【讨论】:

    • 你对重构代码有什么建议吗?如果 XAML 设计器缺少所需的功能,那么代码隐藏似乎是添加额外功能的好地方。请记住,在单个位置定义和维护的附加属性与在每个 XAML 文件的代码隐藏中编写该代码实际上并不相同。我想这也取决于您在代码隐藏中所做的事情。如果您正在修改数据上下文,那么是的,您可能会导致 MVVM 模式出现问题。但是,如果您只是修改 UI 组件,那可能没问题。
    • 这我一直有一个问题......代码隐藏是一个带有 XAML 代码的部分类......它与 XAML 处于同一级别。如果它可以用来做 UI 相关的活动,那和在 XAML 中做没有什么不同。
    【解决方案3】:

    您可以将 Margin 数据绑定到 MVVM 中的属性(字符串)。在您的 MVVM 中,您只需跟踪各个属性(上、右、下、右)。

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

    【讨论】:

    • 数据绑定到我的视图模型中的属性意味着我的视图模型必须维护一个特定于 UI 设计的值。这打破了 MVVM 模式。
    • 我完全同意你的看法......我们在哪里划定“UI”特定功能之间的界限,比如根据状态为行着色。如果涉及“逻辑”并且代码依赖于“其他”属性,例如服务结果和/或属性,那么 MVVM 就是……或者,您始终可以附加行为。
    【解决方案4】:

    这部分你错了:

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

    错误CS1612:无法修改返回值 'System.Windows.FrameworkElement.Margin' 因为它不是变量

    已经不是有效的代码,因为 Margin 返回一个struct,因此是一个值类型。而且因为它不是从 DependencyObject 派生的,所以很多 DataBinding 技巧也不起作用。

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

    【讨论】:

    • @dowhilefor 你对代码隐藏部分是正确的。错字就我而言。我已经更新了我的问题以反映我的实际意思。但是,DataBinding 将起作用,因为 MarginRight 属性是 DependencyObject。因此,每当通过绑定更改属性值时,都会在回调方法中相应地调整 Margin。
    • @bugged87 我对数据绑定的意思是原始问题,而不是您附加的属性答案。当然有数据绑定。但是在一个结构上,即厚度是,你不能使用数据绑定,除非它当然是源。简而言之,我不是在谈论 MarginRight,而是在谈论 Margin.Right。
    猜你喜欢
    • 2021-06-14
    • 2016-02-18
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    相关资源
    最近更新 更多