【问题标题】:Silverlight UserControl and MVVMSilverlight 用户控件和 MVVM
【发布时间】:2010-10-31 20:35:38
【问题描述】:

我有一个与this post 中描述的非常相似的问题。

我有一个 UserControl 来封装地址。这包含许多基本控件,主要是文本框。然后,我在每个属性的代码隐藏中都有支持依赖属性...

#region Line1

    /// <summary> 
    /// Gets or sets the Line1.
    /// </summary> 
    public string Line1
    {
        get
        {
            return (string)GetValue(Line1Property);
        }

        set
        {
            SetValue(Line1Property, value);
        }
    }

    /// <summary> 
    /// The Line1 dependency property.
    /// </summary> 
    public static readonly DependencyProperty Line1Property =
                DependencyProperty.Register(
                      "Line1",
                      typeof(string),
                      typeof(AddressControl),
                      new PropertyMetadata(OnLine1PropertyChanged));

    /// <summary>
    /// Line1Property property changed handler. 
    /// </summary>
    /// <param name="d">AddressControl that changed its Line1.</param>
    /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
    private static void OnLine1PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as AddressControl;
        if (control != null)
        {
            control.OnLine1Changed((string)e.OldValue, (string)e.NewValue);
        }
    }

    /// <summary>
    /// Called when the Line1 changes.
    /// </summary>
    /// <param name="oldValue">The old value.</param>
    /// <param name="newValue">The new value.</param>
    private void OnLine1Changed(string oldValue, string newValue)
    {
        Line1TextBox.Text = newValue;
    }

    #endregion Line1

然后我在视图中使用这个控件...

<myControls:AddressControl Grid.Row="0" Grid.Column="3" 
                           Line1="{Binding Path=Line1, Mode=TwoWay}"/>

这似乎在更新视图模型属性时设置了文本框值,正如您所期望的那样,但是我的问题是从用户控件获取更新回视图模型?

根据上面的链接,我应该检查控件上的 DataContext。 Surley的DataContext会和parent一样吗?

我希望这个问题的答案将适用于多个嵌套级别的控件,即。 Control1 用在 Control2 中,Control2 用在 Control3 中,重用的重点!

把我逼疯了,所以任何帮助真的很感激。

【问题讨论】:

    标签: silverlight mvvm user-controls


    【解决方案1】:

    在 MVVM 中,您应该绑定到 ViewModel 属性,而不是绑定到控件代码隐藏中定义的属性

    【讨论】:

    • 感谢您花时间回答。如果我理解你,我同意应该绑定视图上的自定义用户控件的属性。但是我不能直接绑定到底层文本框,因为这会将绑定限制为一个实例。如果我直接在用户控件中绑定到“Line1”并在页面中使用它,那么我可以在 VM 中创建一个名为 Line1 的属性,因为数据上下文被传递下来。问题是我需要重用 line1 文本框并将其绑定到不同的 VM 属性。例如 ClientLine1、AnotherLine1。因此,UC 首先要重用。
    • 如果您的意思是绑定到控件的支持 VM 类,正如我在答案末尾提到的或由 JamesC78 制作的,那么您是对的。
    【解决方案2】:

    我认为我最初对自己的解释不够好,也认为我找到了解决方案。

    为他人;我的目标是创建一个简单的用户控件来封装由文本框组成的地址(第 1 - 4 行和邮政编码,告诉你这很简单),以便在许多页面上使用(有时在同一页面上使用多次)。这些页面(视图)中的每一个都由 MVVM 模式中的 ViewModel 支持。到目前为止,这都是标准的。我想不通的是如何更改这些文本框中的任何一个以传播到包含 AddressControl 的页面的 ViewModel。和我一起?

    事实证明解决方案(现在看起来很明显)是处理每个文本框失去焦点并更新依赖属性,这会导致绑定触发到视图模型。

    private void AddressTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            switch (((TextBox)sender).Name)
            {
                case "Line1TextBox":
                    Line1 = Line1TextBox.Text;
                    break;
    
                case "Line2TextBox":
                    Line2 = Line2TextBox.Text;
                    break;
    
                case "Line3TextBox":
                    Line3 = Line3TextBox.Text;
                    break;
    
                case "Line4TextBox":
                    Line4 = Line4TextBox.Text;
                    break;
    
                case "LinePostcodeTextBox":
                    Postcode = PostcodeTextBox.Text;
                    break;
            }
        }
    

    另一个选项是将文本框绑定到控件代码隐藏中的支持 ViewModel,并对此进行更改以更新控件。使用本地绑定而不是处理事件的效果相同。

    【讨论】:

    • 您不需要处理事件来更新数据上下文 - 该功能由 SL 数据绑定提供。
    • 哇!一个可能的问题可能是文本框绑定本身缺少“Mode=TwoWay”。你有它的控件,但可能不是文本框
    • 是我 SL 体验的开始,一年多以前,所以记不得了。从那以后学到了很多东西。
    【解决方案3】:

    看起来 UserControl 背后的代码被用来提供控件本身绑定的属性。在这种情况下,您可能有一些像“this.DataContext = this”或“this.AddressLine1Control.DataContext = this”这样的代码,这可能会出现问题(它甚至会导致 SL2 崩溃)。创建一个单独的类来保存您的数据属性,然后执行“this.DataContext = new MyAddressClass()”之类的操作。您会注意到 DataContext 会一直沿控件树向下传播,因此嵌套控件会按照您的预期继承其父级的 DataContext。

    此外,您在这里似乎不需要 DependencyProperties。改为创建传统的 CLR 属性并在您的数据类上实现 INotifyPropertyChanged 接口会更简单(假设您将数据与 UserControl 类分开)。这是在 SL2 中进行数据绑定的标准和推荐方法。

    【讨论】:

    • 代码隐藏提供了与其他“页面”绑定的属性,因此据我所知需要 DP,因为您看不到正常的 CLR 属性。即 或者我正在尝试 。这些恰好与文本框是一对一的。还有一些只是属性,不受控件支持。
    • 我还发现 DataContext = 这个问题,正如您正确指出的那样,我可以将控件中的文本框绑定到支持类。 另一个选项是将文本框绑定到控件代码隐藏中的支持 ViewModel 并对此进行更改以更新控件。使用本地绑定而不是处理事件的效果相同。。我只是选择了事件处理,因为无论如何我都在做其他事情。不过,对于 cmets 来说,如果我能早点找到像你这样的答案,真的可以让我省去很多头痛。
    猜你喜欢
    • 1970-01-01
    • 2012-08-12
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 2011-03-21
    • 1970-01-01
    • 2019-01-13
    相关资源
    最近更新 更多